Railway Operation Simulator  v2.5.1
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal): SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
74  else if(SpeedTagVal == 77)
76  else if(SpeedTagVal == 78)
78  else if(SpeedTagVal == 79)
80  else if(SpeedTagVal == 96)
82  else if(SpeedTagVal == 129)
84  else if(SpeedTagVal == 130)
86  else if(SpeedTagVal == 131)
88  else if(SpeedTagVal == 145)
90  else if(SpeedTagVal == 146)
92 }
93 
94 // ---------------------------------------------------------------------------
95 
96 TFixedTrackPiece::TFixedTrackPiece(): SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
97  FixedNamedLocationElement(false) // default values
98 {
99  for(int x = 0; x < 4; x++)
100  {
101  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
102  Config[x] = NotSet;
103  }
104 }
105 
106 // ---------------------------------------------------------------------------
107 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
108 {
109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
110  AnsiString(VLocInput));
111  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
112  Utilities->CallLogPop(1331);
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 // VARIABLE TRACK :-
118 
119 // ---------------------------------------------------------------------------
120 
122 {
123  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
124  return true;
125  else
126  return false;
127 }
128 
129 // ---------------------------------------------------------------------------
130 
132 {
133  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
134  return true;
135  else
136  return false;
137 }
138 
139 // ---------------------------------------------------------------------------
140 
142  // 'Variable' in the sense that element might be striped or non-striped
143 {
144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
145  Graphics::TBitmap *GraphicOutput = GraphicPtr;
146 
147  if(LocationName == "")
148  {
149  switch(SpeedTag)
150  {
151  case 76: // t platform
152  GraphicOutput = RailGraphics->gl76Striped;
153  break;
154 
155  case 77: // h platform
156  GraphicOutput = RailGraphics->bm77Striped;
157  break;
158 
159  case 78: // v platform
160  GraphicOutput = RailGraphics->bm78Striped;
161  break;
162 
163  case 79: // r platform
164  GraphicOutput = RailGraphics->gl79Striped;
165  break;
166 
167  case 96: // concourse
168  GraphicOutput = RailGraphics->ConcourseStriped;
169  break;
170 
171  case 129: // v footbridge
172  GraphicOutput = RailGraphics->gl129Striped;
173  break;
174 
175  case 130: // h footbridge
176  GraphicOutput = RailGraphics->gl130Striped;
177  break;
178 
179  case 131: // non-station named loc
180  GraphicOutput = RailGraphics->bmNameStriped;
181  break;
182 
183  case 145: // v underpass
184  GraphicOutput = RailGraphics->gl145Striped;
185  break;
186 
187  case 146: // h underpass
188  GraphicOutput = RailGraphics->gl146Striped;
189  break;
190 
191  default:
192  GraphicOutput = GraphicPtr;
193  break;
194  }
195  }
196  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
197  Utilities->CallLogPop(1332);
198 }
199 
200 // ---------------------------------------------------------------------------
201 
202 AnsiString TTrackElement::LogTrack(int Caller) const
203  // for debugging when passes as a call parameter
204 {
205  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
206  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
207 
208  return LogString;
209 }
210 
211 // ---------------------------------------------------------------------------
212 
213 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
214 {
215  if(lower.second < higher.second)
216  {
217  return true;
218  }
219  else if(lower.second > higher.second)
220  {
221  return false;
222  }
223  else if(lower.second == higher.second)
224  {
225  if(lower.first < higher.first)
226  {
227  return true;
228  }
229  }
230  return false;
231 }
232 
233 // ---------------------------------------------------------------------------
234 // PrefDirElement Functions
235 // ---------------------------------------------------------------------------
236 
237 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
238  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
239  CheckCount(9), IsARoute(false), AutoSignals(false), ConsecSignals(false)
240 {
241  if(!EntryExitNumber())
242  {
243  throw Exception("EXNumber failure in TPrefDirElement constructor");
244  }
247 }
248 
249 // ---------------------------------------------------------------------------
250 
251 AnsiString TPrefDirElement::LogPrefDir() const
252  // for debugging when passed as a call parameter
253 {
254  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
255  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)ConsecSignals) +
256  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
257  AnsiString(TrainIDOnBridgeTrackPos23);
258 
259 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
260  return LogString;
261 }
262 
263 // ---------------------------------------------------------------------------
264 
265 bool TPrefDirElement::EntryExitNumber() // true for valid number
266 /*
267  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
268  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
269  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
270  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
271  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
272  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
273  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
274  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
275  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
276 */
277 
278 {
279  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
280  int EXArray[16][2] =
281  {{4, 6}, {2, 8}, // horizontal & vertical
282  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
283  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
284  {1, 9}, {3, 7}}; // forward & reverse diagonals
285 
286  int EXNum = -1;
287  int Entry, Exit;
288 
289  if(ELink > -1)
290  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
291  else if(Link[2] == -1)
292  Entry = Link[0];
293  else
294  {
295  Utilities->CallLogPop(122);
296  return false;
297  }
298  if(XLink > -1)
299  Exit = XLink;
300  else if(Link[2] == -1)
301  Exit = Link[1];
302  else
303  {
304  Utilities->CallLogPop(123);
305  return false;
306  }
307 
308  for(int x = 0; x < 16; x++)
309  {
310  if((Entry == EXArray[x][0]) && (Exit == EXArray[x][1]) || (Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))
311  {
312  EXNum = x;
313  }
314  }
315  if(EXNum == -1)
316  {
317  Utilities->CallLogPop(124);
318  return false;
319  }
320 
321  int BrNum = -1;
322 
323 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
324  the graphic for each of which is different because of the shape of the overbridge. The basic
325  entry/exit value is computed above, and this used to select only from elements with that entry/exit
326  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
327  int BrEXArray[24][2] = {
328  {4,6},{2,8},{1,9},{3,7},
329  {1,9},{3,7},{1,9},{3,7},
330  {2,8},{4,6},{2,8},{4,6}
331 */
332 
333  if(TrackType == Bridge)
334  {
335  if(EXNum == 1)
336  {
337  if(SpeedTag == 49)
338  BrNum = 1 + 16;
339  else if(SpeedTag == 54)
340  BrNum = 8 + 16;
341  else if(SpeedTag == 55)
342  BrNum = 10 + 16;
343  }
344  else if(EXNum == 0)
345  {
346  if(SpeedTag == 48)
347  BrNum = 0 + 16;
348  else if(SpeedTag == 58)
349  BrNum = 11 + 16;
350  else if(SpeedTag == 59)
351  BrNum = 9 + 16;
352  }
353  else if(EXNum == 14)
354  {
355  if(SpeedTag == 50)
356  BrNum = 2 + 16;
357  else if(SpeedTag == 52)
358  BrNum = 4 + 16;
359  else if(SpeedTag == 57)
360  BrNum = 6 + 16;
361  }
362  else if(EXNum == 15)
363  {
364  if(SpeedTag == 51)
365  BrNum = 3 + 16;
366  else if(SpeedTag == 53)
367  BrNum = 7 + 16;
368  else if(SpeedTag == 56)
369  BrNum = 5 + 16;
370  }
371  }
372  if(BrNum == -1)
373  EXNumber = EXNum;
374  else
375  EXNumber = BrNum;
376  Utilities->CallLogPop(125);
377  return true;
378 }
379 
380 // ---------------------------------------------------------------------------
381 
383 /*
384  This is the basic track graphic for use in plotting the original graphic during route flashing.
385  Enter with all set apart from EXGraphic & EntryDirectionGraphic
386 */
387 {
388  if(SpeedTag == 64)
389  return RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers
390 
391  if(SpeedTag == 65)
392  return RailGraphics->LinkGraphicsPtr[17];
393 
394  if(SpeedTag == 66)
395  return RailGraphics->LinkGraphicsPtr[18];
396 
397  if(SpeedTag == 67)
398  return RailGraphics->LinkGraphicsPtr[19];
399 
400  if(SpeedTag == 80)
401  return RailGraphics->LinkGraphicsPtr[20]; // intercept continuations
402 
403  if(SpeedTag == 81)
404  return RailGraphics->LinkGraphicsPtr[21];
405 
406  if(SpeedTag == 82)
407  return RailGraphics->LinkGraphicsPtr[22];
408 
409  if(SpeedTag == 83)
410  return RailGraphics->LinkGraphicsPtr[23];
411 
412  if(SpeedTag == 84)
413  return RailGraphics->LinkGraphicsPtr[24];
414 
415  if(SpeedTag == 85)
416  return RailGraphics->LinkGraphicsPtr[25];
417 
418  if(SpeedTag == 86)
419  return RailGraphics->LinkGraphicsPtr[26];
420 
421  if(SpeedTag == 87)
422  return RailGraphics->LinkGraphicsPtr[27];
423 
424  if(SpeedTag == 129)
425  return RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
426 
427  if(SpeedTag == 130)
428  return RailGraphics->LinkGraphicsPtr[29];
429 
430  if(XLinkPos == -1) // not set, could be first element or last element = leading point
431  {
432 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
433 // Points & don't want to display these)
434  if(Link[2] != -1)
435  return 0; // i.e. complex element, don't display
436  else
437  {
438  if(!EntryExitNumber())
439  {
440  throw Exception("Error in EntryExitNumber 4");
441  }
442  else
443  {
445  }
446  }
447  }
448  if(EXNumber > 15) // underbridge
449  {
451  }
452  else
453  {
455  }
456 }
457 
458 // ---------------------------------------------------------------------------
459 
461 /*
462  As above but for PrefDir graphics.
463 */
464 {
465  if(SpeedTag == 64)
466  return RailGraphics->LinkPrefDirGraphicsPtr[16]; // intercept diagonal buffers
467 
468  if(SpeedTag == 65)
470 
471  if(SpeedTag == 66)
473 
474  if(SpeedTag == 67)
476 
477  if(SpeedTag == 80)
478  return RailGraphics->LinkPrefDirGraphicsPtr[20]; // intercept continuations
479 
480  if(SpeedTag == 81)
482 
483  if(SpeedTag == 82)
485 
486  if(SpeedTag == 83)
488 
489  if(SpeedTag == 84)
491 
492  if(SpeedTag == 85)
494 
495  if(SpeedTag == 86)
497 
498  if(SpeedTag == 87)
500 
501  if(SpeedTag == 129)
502  return RailGraphics->LinkPrefDirGraphicsPtr[28]; // intercept under footbridges
503 
504  if(SpeedTag == 130)
506 
507  if(XLinkPos == -1) // not set, could be first element or last element = leading point
508  {
509 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
510  if(Link[2] != -1)
511  return 0; // i.e. complex element, don't display
512  else
513  {
514  if(!EntryExitNumber())
515  {
516  throw Exception("Error in EntryExitNumber 5");
517  }
518  else
520  }
521  }
522  if(EXNumber > 15) // underbridge
523  {
525  }
526  else
528 }
529 
530 // ---------------------------------------------------------------------------
531 
532 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
533 /*
534  As above but for route graphics.
535 */
536 {
537  if(!AutoSigsFlag && !ConsecSignalsRoute)
538  {
539  if(SpeedTag == 64)
540  return RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers
541 
542  if(SpeedTag == 65)
544 
545  if(SpeedTag == 66)
547 
548  if(SpeedTag == 67)
550 
551  if(SpeedTag == 80)
552  return RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations
553 
554  if(SpeedTag == 81)
556 
557  if(SpeedTag == 82)
559 
560  if(SpeedTag == 83)
562 
563  if(SpeedTag == 84)
565 
566  if(SpeedTag == 85)
568 
569  if(SpeedTag == 86)
571 
572  if(SpeedTag == 87)
574 
575  if(SpeedTag == 129)
576  return RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
577 
578  if(SpeedTag == 130)
580 
581  if(XLinkPos == -1) // not set, could be first element or last element = leading point
582  {
583  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
584  if(Link[2] != -1)
585  return 0; // i.e. complex element, don't display
586  else
587  {
588  if(!EntryExitNumber())
589  {
590  throw Exception("Error in EntryExitNumber 6");
591  }
592  else
594  }
595  }
596  if(EXNumber > 15) // underbridge
597  {
599  }
600  else
602  }
603 
604  else if(!AutoSigsFlag && ConsecSignalsRoute)
605  {
606  if(SpeedTag == 64)
607  return RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers
608 
609  if(SpeedTag == 65)
611 
612  if(SpeedTag == 66)
614 
615  if(SpeedTag == 67)
617 
618  if(SpeedTag == 80)
619  return RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations
620 
621  if(SpeedTag == 81)
623 
624  if(SpeedTag == 82)
626 
627  if(SpeedTag == 83)
629 
630  if(SpeedTag == 84)
632 
633  if(SpeedTag == 85)
635 
636  if(SpeedTag == 86)
638 
639  if(SpeedTag == 87)
641 
642  if(SpeedTag == 129)
643  return RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
644 
645  if(SpeedTag == 130)
647 
648  if(XLinkPos == -1) // not set, could be first element or last element = leading point
649  {
650  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
651  if(Link[2] != -1)
652  return 0; // i.e. complex element, don't display
653  else
654  {
655  if(!EntryExitNumber())
656  {
657  throw Exception("Error in EntryExitNumber 10");
658  }
659  else
661  }
662  }
663  if(EXNumber > 15) // underbridge
664  {
666  }
667  else
669  }
670 
671  else
672  {
673  if(SpeedTag == 64)
674  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
675 
676  if(SpeedTag == 65)
678 
679  if(SpeedTag == 66)
681 
682  if(SpeedTag == 67)
684 
685  if(SpeedTag == 80)
686  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
687 
688  if(SpeedTag == 81)
690 
691  if(SpeedTag == 82)
693 
694  if(SpeedTag == 83)
696 
697  if(SpeedTag == 84)
699 
700  if(SpeedTag == 85)
702 
703  if(SpeedTag == 86)
705 
706  if(SpeedTag == 87)
708 
709  if(SpeedTag == 129)
710  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
711 
712  if(SpeedTag == 130)
714 
715  if(XLinkPos == -1) // not set, could be first element or last element = leading point
716  {
717  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
718  if(Link[2] != -1)
719  return 0; // i.e. complex element, don't display
720  else
721  {
722  if(!EntryExitNumber())
723  {
724  throw Exception("Error in EntryExitNumber 11");
725  }
726  else
728  }
729  }
730  if(EXNumber > 15) // underbridge
731  {
733  }
734  else
736  }
737 }
738 
739 // ---------------------------------------------------------------------------
740 
742 /*
743  As above but for route flashing graphics. (Disused - now combined with above)
744 */
745 {
746  if(SpeedTag == 64)
747  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
748 
749  if(SpeedTag == 65)
751 
752  if(SpeedTag == 66)
754 
755  if(SpeedTag == 67)
757 
758  if(SpeedTag == 80)
759  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
760 
761  if(SpeedTag == 81)
763 
764  if(SpeedTag == 82)
766 
767  if(SpeedTag == 83)
769 
770  if(SpeedTag == 84)
772 
773  if(SpeedTag == 85)
775 
776  if(SpeedTag == 86)
778 
779  if(SpeedTag == 87)
781 
782  if(SpeedTag == 129)
783  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
784 
785  if(SpeedTag == 130)
787 
788  if(XLinkPos == -1) // not set, could be first element or last element = leading point
789  {
790 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
791  if(Link[2] != -1)
792  return 0; // i.e. complex element, don't display
793  else
794  {
795  if(!EntryExitNumber())
796  {
797  throw Exception("Error in EntryExitNumber 7");
798  }
799  else
801  }
802  }
803  if(EXNumber > 15) // underbridge
804  {
806  }
807  else
809 }
810 
811 // ---------------------------------------------------------------------------
812 
814 /*
815  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
816 */
817 {
818  if((ELink > 0) && (ELink < 10) && (ELink != 5))
820  else
821  {
822  throw Exception("Error in EntryExitNumber 8");
823  }
824 }
825 
826 // ---------------------------------------------------------------------------
827 
828 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
829 /*
830  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
831 */
832 {
833  if((ELink > 0) && (ELink < 10) && (ELink != 5))
834  {
835  if(!AutoSigsFlag && !ConsecSignalsRoute)
837  else if(!AutoSigsFlag && ConsecSignalsRoute)
839  else
841  }
842  else
843  {
844  throw Exception("Error in EntryExitNumber 9");
845  }
846 }
847 
848 // ---------------------------------------------------------------------------
849 
851 /*
852  Set == operator when TrackVectorPosition, ELink & XLink all same
853 */
854 {
855  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
856  return true;
857  else
858  return false;
859 }
860 
861 // ---------------------------------------------------------------------------
862 
864 /*
865  Set != operator when any of TrackVectorPosition, ELink or XLink different
866 */
867 {
868  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
869  return false;
870  else
871  return true;
872 }
873 
874 // ---------------------------------------------------------------------------
875 // Track functions
876 // ---------------------------------------------------------------------------
877 
878 // ---------------------------------------------------------------------------
879 
880 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
881 {
882  ConsecSignals = false;
883  TrainPassed = false;
884  BarrierState = Up;
885  ChangeDuration = 0.0;
887  HLoc = 0;
888  VLoc = 0;
889  StartTime = TDateTime(0);
890 }
891 
892 // ---------------------------------------------------------------------------
893 
895 {
896 // CurrentSpeedButtonTag = 0; //not assigned yet
897 
898  HLocMin = 2000000000;
899  VLocMin = 2000000000;
900  HLocMax = -2000000000;
901  VLocMax = -2000000000;
902  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
903  CopyFlag = false; // only true for copying, so names aren't copied
904 
905  AnsiString NL = '\n';
906 
907  RouteFailMessage = "Unable to set a route: it may be unreachable; " + NL +
908  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL +
909  "blocked by a train, another route or a changing level crossing; " + NL +
910  "or invalid - possibly due to a preferred direction mismatch or a missed signal in a green or blue route.";
911 
916 
917  int InternalLinkCheckArray[9][2] =
918  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
919 
920 /* array of valid link values for 'old' location and 'new' location, where
921  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
922 
923  for(int x = 0; x < 9; x++)
924  for(int y = 0; y < 2; y++)
925  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
926 
927 // Platform and default track element values
928  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
929 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
930  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
931  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
932  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
933  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, signals, crossovers, bridges, gaps,
934  << 60 << 61 << 62 << 63 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
935  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
936  // elements, & can always use straights so leave out.)
937  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
938 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
939 
940  int HVArray[10][2] =
941  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
942 
943  for(int x = 0; x < 10; x++)
944  for(int y = 0; y < 2; y++)
945  LinkHVArray[x][y] = HVArray[x][y];
946  TrackFinished = false;
947 // DistancesSet = false;
948 
949  TSigElement TempSigTable[40] = // original four aspect
950  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
951  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
952 
955 
958 
959  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
960  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
961 
962  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
963  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
964  {75, 4, RailGraphics->gl75}};
965 
966  for(int x = 0; x < 40; x++)
967  {
968  SigTable[x] = TempSigTable[x];
969  }
970 
971  TSigElement TempSigTableThreeAspect[40] =
972  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
973  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
974 
977 
978  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
979  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
980 
981  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
982  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
983 
984  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
985  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
986  {75, 4, RailGraphics->gl75}};
987 
988  for(int x = 0; x < 40; x++)
989  {
990  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
991  }
992 
993  TSigElement TempSigTableTwoAspect[40] =
994  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
995  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
996 
997  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
998  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
999 
1000  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1001  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1002 
1003  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1004  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1005 
1006  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1007  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1008  {75, 4, RailGraphics->gl75}};
1009 
1010  for(int x = 0; x < 40; x++)
1011  {
1012  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1013  }
1014 
1015  TSigElement TempSigTableGroundSignal[40] =
1019 
1023 
1027 
1031 
1032  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1035 
1036  for(int x = 0; x < 40; x++)
1037  {
1038  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1039  }
1040 
1041 /*
1042  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1043  a single location. These are as follows:-
1044  Directly Adjacent = up, down, left or right - NOT diagonal.
1045  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1046  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1047  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1048 
1049  //t 76
1050  //b 77
1051  //l 78
1052  //r 79
1053  //c 96
1054  //v fb 129
1055  //h fb 130
1056  //v underpass 145
1057  //h underpass 146
1058  //n 131
1059 */
1060 
1061  int Tag76[25][3] =
1062  {{-1, 0, 96}, // c top plat
1063  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1064  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1065  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1066  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1067  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1068  {0, 0, 129}, {0, -1, 145}, // v up
1069  {0, 0, 145}};
1070 
1071  for(int x = 0; x < 25; x++)
1072  for(int y = 0; y < 3; y++)
1073  Tag76Array[x][y] = Tag76[x][y];
1074 
1075  int Tag77[25][3] =
1076  {{-1, 0, 96}, // c bot plat
1077  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1078  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1079  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1080  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1081  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1082  {0, 0, 129}, {0, 1, 145}, // v up
1083  {0, 0, 145}};
1084 
1085  for(int x = 0; x < 25; x++)
1086  for(int y = 0; y < 3; y++)
1087  Tag77Array[x][y] = Tag77[x][y];
1088 
1089  int Tag78[25][3] =
1090  {{-1, 0, 96}, // c left plat
1091  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1092  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1093  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1094  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1095  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1096  {0, 0, 130}, {-1, 0, 146}, // h up
1097  {0, 0, 146}};
1098 
1099  for(int x = 0; x < 25; x++)
1100  for(int y = 0; y < 3; y++)
1101  Tag78Array[x][y] = Tag78[x][y];
1102 
1103  int Tag79[25][3] =
1104  {{-1, 0, 96}, // c right plat
1105  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1106  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1107  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1108  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1109  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1110  {0, 0, 130}, {1, 0, 146}, // h up
1111  {0, 0, 146}};
1112 
1113  for(int x = 0; x < 25; x++)
1114  for(int y = 0; y < 3; y++)
1115  Tag79Array[x][y] = Tag79[x][y];
1116 
1117  int Tag96[28][3] =
1118  {{-1, 0, 96}, // c //concourse
1119  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1120  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1121  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1122  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1123  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1124  {0, -1, 129}, {1, 0, 130}, // h fb
1125  {-1, 0, 130}, {0, 1, 145}, // v up
1126  {0, -1, 145}, {1, 0, 146}, // h up
1127  {-1, 0, 146}};
1128 
1129  for(int x = 0; x < 28; x++)
1130  for(int y = 0; y < 3; y++)
1131  Tag96Array[x][y] = Tag96[x][y];
1132 
1133  int Tag129[8][3] = // vert fb
1134  {{0, -1, 96}, // c
1135  {0, -1, 77}, // b
1136  {0, -1, 129}, // v fb
1137 
1138  {0, 1, 96}, // c
1139  {0, 1, 76}, // t
1140  {0, 1, 129}, // v fb
1141 
1142  {0, 0, 76}, // t
1143  {0, 0, 77}}; // b
1144 
1145  for(int x = 0; x < 8; x++)
1146  for(int y = 0; y < 3; y++)
1147  Tag129Array[x][y] = Tag129[x][y];
1148 
1149  int Tag145[8][3] = // vert up
1150  {{0, -1, 96}, // c
1151  {0, -1, 77}, // b
1152  {0, -1, 145}, // v fb
1153 
1154  {0, 1, 96}, // c
1155  {0, 1, 76}, // t
1156  {0, 1, 145}, // v fb
1157 
1158  {0, 0, 76}, // t
1159  {0, 0, 77}}; // b
1160 
1161  for(int x = 0; x < 8; x++)
1162  for(int y = 0; y < 3; y++)
1163  Tag145Array[x][y] = Tag145[x][y];
1164 
1165  int Tag130[8][3] = // hor fb
1166  {{-1, 0, 96}, // c
1167  {-1, 0, 79}, // r
1168  {-1, 0, 130}, // h fb
1169 
1170  {1, 0, 96}, // c
1171  {1, 0, 78}, // l
1172  {1, 0, 130}, // h fb
1173 
1174  {0, 0, 78}, // l
1175  {0, 0, 79}}; // r
1176 
1177  for(int x = 0; x < 8; x++)
1178  for(int y = 0; y < 3; y++)
1179  Tag130Array[x][y] = Tag130[x][y];
1180 
1181  int Tag146[8][3] = // hor up
1182  {{-1, 0, 96}, // c
1183  {-1, 0, 79}, // r
1184  {-1, 0, 146}, // h fb
1185 
1186  {1, 0, 96}, // c
1187  {1, 0, 78}, // l
1188  {1, 0, 146}, // h fb
1189 
1190  {0, 0, 78}, // l
1191  {0, 0, 79}}; // r
1192 
1193  for(int x = 0; x < 8; x++)
1194  for(int y = 0; y < 3; y++)
1195  Tag146Array[x][y] = Tag146[x][y];
1196 
1197  int Tag131[4][3] =
1198  {{-1, 0, 131}, // n
1199  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1200 
1201  for(int x = 0; x < 4; x++)
1202  for(int y = 0; y < 3; y++)
1203  Tag131Array[x][y] = Tag131[x][y];
1204 
1205  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1206  {0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1207  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1208  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1209  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1210  140, 144, 145, 146};
1211 
1212  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1213  {0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1214  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1215  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1216  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1217  141, 144, 145, 146};
1218 
1219  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1220  {0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1221  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1222  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1223  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1224  141, 144, 146, 145};
1225 
1226  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1227  {0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1228  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1229  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1230  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1231  140, 144, 146, 145};
1232 
1233  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1234  {
1235  FlipArray[x] = InternalFlipArray[x];
1236  MirrorArray[x] = InternalMirrorArray[x];
1237  RotRightArray[x] = InternalRotRightArray[x];
1238  RotLeftArray[x] = InternalRotLeftArray[x];
1239  }
1240 }
1241 
1242 // ---------------------------------------------------------------------------
1244 {
1245 // delete TrackVectorPtr;
1246 // delete FixedTrackArrayPtr;
1247  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1248 
1249  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1250  {
1251  delete UGMIt->second;
1252  UGMIt++;
1253  }
1254  delete GapFlashGreen;
1255  delete GapFlashRed;
1256  // all the rest are cleared by the relevant automatic destructors
1257 }
1258 
1259 // ---------------------------------------------------------------------------
1260 
1262 {
1263  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1264  {
1265 // loc 0 not used, set to bmSolidBgnd
1269 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1289 
1290  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1291  {
1292 // loc 0 not used, set to smSolidBgnd
1296 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1315  RailGraphics->smTransparent, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1316  };
1317 
1318 // track types
1319  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1320  {Erase, // 1 0
1321  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1322  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1323  Crossover, Crossover, // 2 15-16
1324  Unused, // 17 (was for text in earlier development) //1 17
1327  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1331  Platform, Platform, Platform, Platform, // 4 76-79
1334  Concourse, // 1 96
1337  Simple, Simple, Simple, Simple, // 4 125-128
1338  FootCrossing, FootCrossing, // 2 129-130
1339  NamedNonStationLocation, // 1 131
1340  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1341  Simple, Simple, Simple, Simple, // 4 140-143
1342  LevelCrossing, // 1 144
1343  FootCrossing, FootCrossing // 2 145 & 146
1344  };
1345 
1346 // links
1347  int Links[FirstUnusedSpeedTagNumber][4] =
1348  {{-1, -1, -1, -1}, // erase element
1349  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1350  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1351 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1352  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1353  {-1, -1, -1, -1}, // unused
1354  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1355  {2, 7, -1, -1}, // simple
1356  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8
1357  }, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1358 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1359 // (or right diverging if no straight)
1360  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1361  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6
1362  }, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1363  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1364  }, // buffers - position 0 = buffer
1365  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1
1366  }, // signals (need Config to determine signal end, see below)
1367  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1368  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1369  }, // continuation - position 0 = continuation
1370  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1371  }, // gapjump - position 0 = gap
1372  {-1, -1, -1, -1}, // Concourse
1373  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1374  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1375  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1376  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1377  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1378  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1379  {-1, -1, -1, -1}, // NamedNonStationLocation
1380  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1381 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1382  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1383  {-1, -1, -1, -1}, // level crossing
1384  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1385  };
1386 
1388  {{NotSet, NotSet, NotSet, NotSet}, // unused
1392  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1394  {NotSet, NotSet, NotSet, NotSet}, // unused
1398  {Connection, Connection, NotSet, NotSet}, // simple
1402  {Lead, Trail, Lead, Trail}, // points
1404  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1413  }, // signals (signal at exit end in forward direction)
1417  }, // continuation
1420  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1429  {Connection, Connection, NotSet, NotSet}, // Arrows
1431  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1433  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1435  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1436  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1437  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1438  };
1439 
1440  for(int x = 0; x < 17; x++)
1441  {
1442  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1443  }
1444  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1445 // 17 was the old text value so don't want any graphics (now disused)
1446  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1447  {
1448  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1449  }
1450 }
1451 
1452 // ---------------------------------------------------------------------------
1453 TGraphicElement::TGraphicElement(): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1454  ExistingGraphicLoaded(false), Width(16), Height(16)
1455 {
1456  OriginalGraphic = new Graphics::TBitmap;
1457  OriginalGraphic->PixelFormat = pf8bit;
1458  OriginalGraphic->Width = Width;
1459  OriginalGraphic->Height = Height;
1460  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1461 }
1462 
1463 // ---------------------------------------------------------------------------
1464 
1465 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1466  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1467 {
1468  OriginalGraphic = new Graphics::TBitmap;
1469  OriginalGraphic->PixelFormat = pf8bit;
1470  OriginalGraphic->Width = Width;
1471  OriginalGraphic->Height = Height;
1472  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1473 }
1474 
1475 // ---------------------------------------------------------------------------
1476 
1478 {
1479  delete OriginalGraphic;
1480 }
1481 
1482 // ---------------------------------------------------------------------------
1483 
1484 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1485 {
1486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1487  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1488  VPos = VPosIn;
1489  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1490 
1491  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1492  SourceRect.init(Left, Top, Left + Width, Top + Height);
1493  ScreenSourceSet = true;
1494  Utilities->CallLogPop(422);
1495 }
1496 
1497 // ---------------------------------------------------------------------------
1498 
1500 {
1501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1502  if(!OverlayLoaded)
1503  {
1504  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1505  }
1506  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1507  {
1508  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1509  }
1510  if(!ScreenSourceSet)
1511  {
1512  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1513  }
1514  if(ExistingGraphicLoaded) // can only call one of the load functions
1515  {
1516  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1517  }
1518  if(OverlayPlotted) // don't load from screen if overlay plotted
1519  {
1520  Utilities->CallLogPop(775);
1521  return;
1522  }
1523  TRect DestRect(0, 0, Width, Height);
1524 
1526  OriginalLoaded = true;
1527  ScreenGraphicLoaded = true;
1528  Utilities->CallLogPop(423);
1529 }
1530 
1531 // ---------------------------------------------------------------------------
1532 
1533 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1534 /*
1535  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1536 */
1537 {
1538  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1539  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1540  if(!OverlayLoaded)
1541  {
1542  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1543  }
1544  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1545  {
1546  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1547  }
1548  if(ScreenGraphicLoaded) // can only call one of the load functions
1549  {
1550  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1551  }
1552  Width = WidthIn;
1553  Height = HeightIn;
1554  OriginalGraphic->Width = Width;
1555  OriginalGraphic->Height = Height;
1556  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1557  VPos += VOffset;
1558  TRect DestRect(0, 0, Width, Height);
1559 
1560  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1561  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1562  OriginalLoaded = true;
1563  ExistingGraphicLoaded = true;
1564  Utilities->CallLogPop(424);
1565 }
1566 
1567 // ---------------------------------------------------------------------------
1568 
1569 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1570 {
1571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1572  OverlayGraphic = Overlay;
1573  OverlayLoaded = true;
1574  Utilities->CallLogPop(425);
1575 }
1576 
1577 // ---------------------------------------------------------------------------
1578 
1580 {
1581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1582  if(!OverlayLoaded)
1583  {
1584  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1585  }
1586  if(!OverlayPlotted)
1587  {
1588  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1589  Disp->Update();
1590  OverlayPlotted = true;
1591  }
1592  Utilities->CallLogPop(426);
1593 }
1594 
1595 // ---------------------------------------------------------------------------
1596 
1598 {
1599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1600  if(OverlayPlotted)
1601  {
1602  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1603  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1604  {
1605  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1606  }
1607  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1608  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1609  OverlayPlotted = false;
1610  }
1611  Utilities->CallLogPop(427);
1612 }
1613 
1614 // ---------------------------------------------------------------------------
1615 
1617 {
1618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1619  bool TrackPresent = false;
1620 
1621  if(InactiveTrackVector.size() != 0)
1622  {
1623  Utilities->CallLogPop(1333);
1624  return false;
1625  }
1626  else if(TrackVector.size() == 0)
1627  {
1628  Utilities->CallLogPop(1334);
1629  return true;
1630  }
1631  else
1632  {
1633  for(unsigned int x = 0; x < TrackVector.size(); x++)
1634  {
1635  if((TrackVector.at(x).SpeedTag != 0))
1636  TrackPresent = true;
1637  }
1638  }
1639  Utilities->CallLogPop(1335);
1640  return !TrackPresent;
1641 }
1642 
1643 // ---------------------------------------------------------------------------
1644 
1645 bool TTrack::NoActiveTrack(int Caller)
1646 {
1647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1648  bool TrackPresent = false;
1649 
1650  if(TrackVector.size() == 0)
1651  {
1652  Utilities->CallLogPop(1582);
1653  return true;
1654  }
1655  else
1656  {
1657  for(unsigned int x = 0; x < TrackVector.size(); x++)
1658  {
1659  if((TrackVector.at(x).SpeedTag != 0))
1660  TrackPresent = true;
1661  break;
1662  }
1663  }
1664  Utilities->CallLogPop(1583);
1665  return !TrackPresent;
1666 }
1667 
1668 // ---------------------------------------------------------------------------
1669 
1670 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1671 {
1672  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1673  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1674  TrackEraseSuccessfulFlag = false;
1675 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1676 // since have to match platforms as well as track
1677 // used to set TrackFinished to false if an element erased
1678 
1679  ErasedTrackVectorPosition = -1; // marker for no element erased
1680  AnsiString SName = "", ErrorString;
1682  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1683  TTrackMapIterator TrackMapPtr;
1684  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1685 
1686  if(TrackVector.size() != 0)
1687  {
1688  TrackMapKeyPair.first = HLocInput;
1689  TrackMapKeyPair.second = VLocInput;
1690  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1691  if(TrackMapPtr != TrackMap.end())
1692  {
1693  bool FoundFlag;
1694  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1695  if(FoundFlag) // should find it as it's in the map
1696  {
1697  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1698  {
1699  SName = TrackElementAt(1, VecPos).LocationName;
1700  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1701  if(ErrorString != "")
1702  {
1703  throw Exception(ErrorString + " for EraseTrackElement 1");
1704  }
1705  LocationNameMultiMap.erase(SNIt);
1706  }
1707 
1708  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1709  // ensure erase vector element before map element as iterator no longer valid after a map erase
1710  TrackMap.erase(TrackMapPtr);
1711  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1712  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1714  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1715  if(SName != "")
1716  {
1717  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1718  int HPos, VPos;
1719  if(TextHandler->FindText(1, SName, HPos, VPos))
1720  {
1721  if(TextHandler->TextErase(5, HPos, VPos, SName))
1722  {;
1723  } // condition not used
1724  }
1725  }
1726  ErasedTrackVectorPosition = VecPos;
1727  TrackEraseSuccessfulFlag = true;
1728  }
1729  }
1730  }
1731 
1732  if(InactiveTrackVector.size() != 0)
1733  {
1734  unsigned int VecPos;
1735  InactiveTrackMapKeyPair.first = HLocInput;
1736  InactiveTrackMapKeyPair.second = VLocInput;
1737  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
1738  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1739  {
1740  SName = "";
1741  VecPos = InactiveTrack2MultiMapIterator->second;
1742  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
1743  {
1744  SName = InactiveTrackElementAt(1, VecPos).LocationName;
1745  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1746  if(ErrorString != "")
1747  {
1748  throw Exception(ErrorString + " for EraseTrackElement 2A");
1749  }
1750  LocationNameMultiMap.erase(SNIt);
1751  }
1752  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1753  // ensure erase vector element before map element as iterator no longer valid after a map erase
1754  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1755  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
1756  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1758  TrackEraseSuccessfulFlag = true;
1759  if(SName != "")
1760  {
1761  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1762  int HPos, VPos;
1763  if(TextHandler->FindText(2, SName, HPos, VPos))
1764  {
1765  if(TextHandler->TextErase(6, HPos, VPos, SName))
1766  {;
1767  } // condition not used
1768  }
1769  }
1770  }
1771 
1772  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
1773  {
1774  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
1775  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1776  {
1777  SName = "";
1778  VecPos = InactiveTrack2MultiMapIterator->second;
1779  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
1780  {
1781  SName = InactiveTrackElementAt(3, VecPos).LocationName;
1782  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1783  if(ErrorString != "")
1784  {
1785  throw Exception(ErrorString + " for EraseTrackElement 2B");
1786  }
1787  LocationNameMultiMap.erase(SNIt);
1788  }
1789  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1790  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1791  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1793  if(SName != "")
1794  {
1795  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1796  int HPos, VPos;
1797  if(TextHandler->FindText(3, SName, HPos, VPos))
1798  {
1799  if(TextHandler->TextErase(7, HPos, VPos, SName))
1800  {;
1801  } // condition not used
1802  }
1803  }
1804  }
1805  }
1806  }
1807  if(TrackEraseSuccessfulFlag)
1808  {
1809  CalcHLocMinEtc(2);
1810  SetTrackFinished(false);
1811  }
1812  if(InternalChecks)
1813  {
1814  CheckMapAndTrack(1); // test
1815  CheckMapAndInactiveTrack(1); // test
1816  CheckLocationNameMultiMap(6); // test
1817  }
1818  Utilities->CallLogPop(428);
1819 }
1820 
1821 // ---------------------------------------------------------------------------
1822 
1823 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
1824  // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
1825  // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
1826  // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
1827 {
1828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
1829  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1830  bool PlatAllowedFlag = false;
1831 
1832  TrackLinkingRequiredFlag = false;
1833 /*
1834  Not erase, that covered separately.
1835  First check if Current SpeedButton assigned, then check if a platform and only
1836  permit if an appropriate trackpiece already there & not a same platform there.
1837  - can't enter a platform without track first.
1838  Then for non-platforms, check if a track piece already present at location &
1839  reject if so.
1840 */
1841 
1842  TLocationNameMultiMapEntry LocationNameEntry;
1843 
1844  LocationNameEntry.first = "";
1845  if(CurrentTag == 0)
1846  {
1847  Utilities->CallLogPop(429);
1848  return; // not assigned yet
1849  }
1850 
1851  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
1852 
1853  TempTrackElement.HLoc = HLocInput;
1854  TempTrackElement.VLoc = VLocInput;
1855  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
1856 // new at version 0.6 - set signal aspect depending on build mode
1857 
1858  if(TempTrackElement.TrackType == SignalPost)
1859  {
1860  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
1861  // pasting a SignalPost can only have values 1 to 4
1862  {
1864  {
1865  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1866  }
1868  {
1869  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1870  }
1872  {
1873  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1874  }
1875  else
1876  {
1877  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1878  }
1879  }
1880  else if(Aspect == 1)
1881  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1882  else if(Aspect == 2)
1883  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1884  else if(Aspect == 3)
1885  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1886  else
1887  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1888  }
1889 
1890  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
1891  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
1892  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
1893  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
1894 
1895  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
1896  {
1898  NonStationOrLevelCrossingPresent = true;
1899  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
1900  NonStationOrLevelCrossingPresent = true;
1901  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
1902  PlatformPresent = true;
1903  // no need to check IMPair.second since if that exists it is because .first is a platform
1904  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
1905  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
1906  }
1907 
1908 // check platforms
1909  if(TempTrackElement.TrackType == Platform)
1910  {
1911  if(FoundFlag) // active track element already there
1912  {
1913  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
1914  {;
1915  }
1916  // same platform type already there so above keeps PlatAllowedFlag false
1917  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1918  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
1919  {
1920  PlatAllowedFlag = true;
1921  }
1922  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1923  {
1924  PlatAllowedFlag = true;
1925  }
1926  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1927  {
1928  PlatAllowedFlag = true;
1929  }
1930  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1931  {
1932  PlatAllowedFlag = true;
1933  }
1934  if(PlatAllowedFlag)
1935  {
1936  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
1937  TrackPush(1, TempTrackElement);
1938  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1939  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1940  // Must be called AFTER TrackPush
1941  // No need to plot the element - Clearand ... called after this function called
1942  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
1943  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
1944 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1945 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
1946 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
1947  if(InternalChecks)
1948  {
1949  CheckMapAndInactiveTrack(5); // test
1950  CheckLocationNameMultiMap(4); // test
1951  }
1952  Utilities->CallLogPop(430);
1953  return;
1954  }
1955  } // if(FoundFlag)
1956  Utilities->CallLogPop(431);
1957  return;
1958  } // if platform
1959 
1960 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
1961  if(TempTrackElement.TrackType == NamedNonStationLocation)
1962  {
1963  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
1964  (!FoundFlag && !InactiveFoundFlag))
1965  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
1966  {
1967  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
1968  TrackPush(2, TempTrackElement);
1969  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1970  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1971  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
1972  {
1973 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1974 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
1975 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
1976  }
1977  if(InternalChecks)
1978  {
1979  CheckMapAndInactiveTrack(11); // test
1980  CheckLocationNameMultiMap(12); // test
1981  }
1982  Utilities->CallLogPop(432);
1983  return;
1984  }
1985  else
1986  {
1987  Utilities->CallLogPop(433);
1988  return;
1989  }
1990  }
1991 
1992 // check if a level crossing - OK if placed on a plain straight track
1993  if(TempTrackElement.TrackType == LevelCrossing)
1994  {
1995  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
1996  {
1997  TrackPush(11, TempTrackElement);
1998  PlotRaisedLinkedLevelCrossingBarriers(0, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display);
1999 // no need for reference to LC element as can't be open
2000  TrackLinkingRequiredFlag = true;
2001  Utilities->CallLogPop(1907);
2002  return;
2003  }
2004  else
2005  {
2006  Utilities->CallLogPop(1906);
2007  return; // was a level crossing but can't place it for some reason
2008  }
2009  }
2010 
2011 // check if another element already there
2012  else if(FoundFlag || InactiveFoundFlag)
2013  {
2014  Utilities->CallLogPop(434);
2015  return; // something already there (active or inactive track)
2016  }
2017 
2018 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2019 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2020 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2021 // do this after pushed into vector so that can use EnterLocationName
2022 
2023  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2024  {
2025  TrackPush(3, TempTrackElement);
2026  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2027  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2028  }
2029  else if(TempTrackElement.TrackType == Points)
2030  {
2031  TrackPush(4, TempTrackElement);
2032  bool BothPointFillets = true;
2033  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2034  }
2035  else if(TempTrackElement.TrackType == SignalPost)
2036  {
2037  TrackPush(10, TempTrackElement);
2038  PlotSignal(12, TempTrackElement, Display);
2039  }
2040  else
2041  {
2042  TrackPush(5, TempTrackElement);
2043  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2044  }
2045  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2046  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2047  if(InternalChecks)
2048  {
2049  CheckMapAndTrack(2); // test
2050  CheckMapAndInactiveTrack(2); // test
2051  CheckLocationNameMultiMap(5); // test
2052  }
2053  Utilities->CallLogPop(2062);
2054 }
2055 
2056 // ---------------------------------------------------------------------------
2057 
2058 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2059  bool InternalChecks)
2060  // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2061  // NB experimental: - need to change all caller numbers & check thoroughly if release
2062  // as is if single elements have location or platform names then have message that names fail to align when mouse over
2063  // need to deal with this if release - it's because ActiveTrackElementName is cleared in the new function, if not a single element
2064  // then set when call SearchForAndUpdateLocationName. Maybe instead of clearing can set to the InactiveTrackElementName at the same location?
2065 {
2066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2067  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2068  bool PlatAllowedFlag = false;
2069 
2070  TrackLinkingRequiredFlag = false;
2071 /*
2072  Not erase, that covered separately.
2073  First check if Current SpeedButton assigned, then check if a platform and only
2074  permit if an appropriate trackpiece already there & not a same platform there.
2075  - can't enter a platform without track first.
2076  Then for non-platforms, check if a track piece already present at location &
2077  reject if so.
2078 */
2079 
2080  TLocationNameMultiMapEntry LocationNameEntry;
2081 
2082  LocationNameEntry.first = "";
2083  if(TempTrackElement.SpeedTag == 0)
2084  {
2085  Utilities->CallLogPop(2063);
2086  return; // not assigned yet
2087  }
2088 
2089  TempTrackElement.HLoc = HLocInput;
2090  TempTrackElement.VLoc = VLocInput;
2091  for(int x = 0; x < 4; x++) // unset any gaps
2092  {
2093  if(TempTrackElement.Config[x] == Gap)
2094  TempTrackElement.ConnLinkPos[x] = -1;
2095  TempTrackElement.Conn[x] = -1;
2096  }
2097  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2098 // new at version 0.6 - set signal aspect depending on build mode
2099  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2100  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2101 
2102  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2103  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2104  // for the active track element because these aren't set
2105  // if don't do this then get a mismatch error during map checks later
2106 
2107  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2108 
2109  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2110  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2111 
2112  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2113  {
2114  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2115  NonStationOrLevelCrossingPresent = true;
2116  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2117  NonStationOrLevelCrossingPresent = true;
2118  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2119  PlatformPresent = true;
2120  // no need to check IMPair.second since if that exists it is because .first is a platform
2121  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2122  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2123  }
2124 
2125 // check platforms
2126  if(TempTrackElement.TrackType == Platform)
2127  {
2128  if(FoundFlag) // active track element already there
2129  {
2130  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2131  {;
2132  }
2133  // same platform type already there so above keeps PlatAllowedFlag false
2134  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2135  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2136  {
2137  PlatAllowedFlag = true;
2138  }
2139  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2140  {
2141  PlatAllowedFlag = true;
2142  }
2143  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2144  {
2145  PlatAllowedFlag = true;
2146  }
2147  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2148  {
2149  PlatAllowedFlag = true;
2150  }
2151  if(PlatAllowedFlag)
2152  {
2153  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2154  TrackPush(12, TempTrackElement);
2155  if(!CopyFlag) // don't need this for copy
2156  {
2157  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2158  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2159  }
2160  // Must be called AFTER TrackPush
2161 // No need to plot the element - Clearand ... called after this function called
2162  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2163  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2164 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2165 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2166 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2167  if(InternalChecks)
2168  {
2169  CheckMapAndInactiveTrack(12); // test
2170  CheckLocationNameMultiMap(20); // test
2171  }
2172  Utilities->CallLogPop(2064);
2173  return;
2174  }
2175  } // if(FoundFlag)
2176  Utilities->CallLogPop(2065);
2177  return;
2178  } // if platform
2179 
2180 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2181  if(TempTrackElement.TrackType == NamedNonStationLocation)
2182  {
2183  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2184  (!FoundFlag && !InactiveFoundFlag))
2185  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2186  {
2187  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2188  TrackPush(13, TempTrackElement);
2189  if(!CopyFlag) // don't need this for copy
2190  {
2191  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2192  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2193  }
2194  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2195  {
2196 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2197 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2198 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2199  }
2200  if(InternalChecks)
2201  {
2202  CheckMapAndInactiveTrack(13); // test
2203  CheckLocationNameMultiMap(21); // test
2204  }
2205  Utilities->CallLogPop(2066);
2206  return;
2207  }
2208  else
2209  {
2210  Utilities->CallLogPop(2067);
2211  return;
2212  }
2213  }
2214 
2215 // check if a level crossing - OK if placed on a plain straight track
2216  if(TempTrackElement.TrackType == LevelCrossing)
2217  {
2218  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2219  {
2220  TrackPush(14, TempTrackElement);
2221  PlotRaisedLinkedLevelCrossingBarriers(3, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display);
2222 // no need for reference to LC element as can't be open
2223  TrackLinkingRequiredFlag = true;
2224  Utilities->CallLogPop(2068);
2225  return;
2226  }
2227  else
2228  {
2229  Utilities->CallLogPop(2069);
2230  return; // was a level crossing but can't place it for some reason
2231  }
2232  }
2233 
2234 // check if another element already there
2235  else if(FoundFlag || InactiveFoundFlag)
2236  {
2237  Utilities->CallLogPop(2070);
2238  return; // something already there (active or inactive track)
2239  }
2240 
2241 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2242 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2243 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2244 // do this after pushed into vector so that can use EnterLocationName
2245 
2246  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2247  {
2248  TrackPush(15, TempTrackElement);
2249  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2250  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2251  }
2252  else if(TempTrackElement.TrackType == Points)
2253  {
2254  TrackPush(16, TempTrackElement);
2255  bool BothPointFillets = true;
2256  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2257  }
2258  else if(TempTrackElement.TrackType == SignalPost)
2259  {
2260  TrackPush(17, TempTrackElement);
2261  PlotSignal(14, TempTrackElement, Display);
2262  }
2263  else
2264  {
2265  TrackPush(18, TempTrackElement);
2266  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2267  }
2268  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2269  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2270  if(InternalChecks)
2271  {
2272  CheckMapAndTrack(12); // test
2273  CheckMapAndInactiveTrack(14); // test
2274  CheckLocationNameMultiMap(22); // test
2275  }
2276  Utilities->CallLogPop(2071);
2277 }
2278 
2279 // ---------------------------------------------------------------------------
2280 
2281 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2282  // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2283  // return bool = true for success
2284  // LocError = true for location error & HLoc & VLoc to be inverted
2285 {
2286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2287  LocError = false;
2288  SetTrackFinished(false);
2289  if(TrackVector.size() == 0)
2290  {
2291  Utilities->CallLogPop(437);
2292  return false;
2293  }
2294  if(GapsUnset(7))
2295  {
2296  if(GiveMessages)
2297  ShowMessage("Gaps must be set before track can be validated");
2298  Utilities->CallLogPop(1135);
2299  return false;
2300  }
2301 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2302 // returns true for any unset gaps
2304  {
2305  // can keep this exception as protected by the GapsUnset call above
2306  throw Exception("Error, gaps unset when TryToConnectTrack called");
2307  }
2309  CheckGapMap(1); // test
2310 // Gap connections now securely defined
2311 
2312  CheckMapAndTrack(8); // test
2313 
2314 // Perform a pre-check prior to TrackMap being compiled
2315  if(GiveMessages)
2316  {
2317  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2318  {
2319  Utilities->CallLogPop(439);
2320  return false;
2321  }
2322  }
2323  else
2324  {
2325  if(!LinkTrackNoMessages(1, false))
2326  {
2327  Utilities->CallLogPop(1131);
2328  return false;
2329  }
2330  }
2331 
2332 // here if pre-check successful
2333  if(!RepositionAndMapTrack(0))
2334  {
2335  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2336  Utilities->CallLogPop(1138);
2337  return false;
2338  }
2339 // now perform the final assembly - FinalCall = true
2340  if(GiveMessages)
2341  {
2342  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2343  {
2344  Utilities->CallLogPop(1116);
2345  return false;
2346  }
2347  }
2348  else
2349  {
2350  if(!LinkTrackNoMessages(2, true))
2351  {
2352  Utilities->CallLogPop(1132);
2353  return false;
2354  }
2355  }
2356 
2357 // success
2358 
2359  PopulateLCVector(0);
2360  CheckGapMap(2); // test
2361  CheckMapAndTrack(3); // test
2362  CheckMapAndInactiveTrack(3); // test
2363  CheckLocationNameMultiMap(9); // test
2364  SetTrackFinished(true);
2365 
2366 // Build ContinuationNameMap
2367  std::pair<AnsiString, char>TempMapPair;
2368 
2369  ContinuationNameMap.clear();
2370  for(int x = 0; x < Track->TrackVectorSize(); x++)
2371  {
2372  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
2373  {
2374  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
2375  TempMapPair.second = 'x'; // unused
2376  ContinuationNameMap.insert(TempMapPair);
2377  }
2378  }
2379  Utilities->CallLogPop(440);
2380  return true;
2381 }
2382 
2383 // ---------------------------------------------------------------------------
2384 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2385  // unused - too time-consuming - double brute force search
2386 {
2387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2388  int NewHLoc, NewVLoc;
2389  bool ConnectionFoundFlag, LinkFoundFlag;
2390 
2391  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2392  {
2393  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2394  {
2395  if(TrackVector.at(x).Link[y] <= 0)
2396  continue; // no link
2397  if(TrackVector.at(x).Config[y] == End)
2398  continue; // buffer or continuation
2399  if(TrackVector.at(x).Config[y] == Gap)
2400  continue; // gap jump
2401  // get required H & V for track element joining link 'y'
2402  NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
2403  NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
2404  // find track element if present
2405  ConnectionFoundFlag = false;
2406  for(unsigned int z = 0; z < TrackVector.size(); z++)
2407  {
2408 // if(TrackElementAt(5, z).TrackType == Platform)
2409 // continue; //skip platforms
2410  if((TrackVector.at(z).HLoc == NewHLoc) && (TrackVector.at(z).VLoc == NewVLoc))
2411  {
2412  ConnectionFoundFlag = true;
2413  // find connecting link in the newly found track element if there is one
2414  LinkFoundFlag = false;
2415  for(unsigned int a = 0; a < 4; a++)
2416  {
2417  if(TrackVector.at(z).Link[a] == (10 - TrackVector.at(x).Link[y]))
2418  {
2419  LinkFoundFlag = true;
2420  }
2421  }
2422  // if there isn't a corresponding link set the invert values for the offending element
2423  if(!LinkFoundFlag)
2424  {
2425  HLoc = TrackVector.at(x).HLoc;
2426  VLoc = TrackVector.at(x).VLoc;
2427  Utilities->CallLogPop(441);
2428  return true;
2429  }
2430  break; // success, so break out of 'z' loop
2431  } // if((TrackVector.at(z).HLoc== NewHLoc) &&....
2432  } // for z...
2433  // if there isn't a connection set the invert values for the offending element
2434  if(!ConnectionFoundFlag)
2435  {
2436  HLoc = TrackVector.at(x).HLoc;
2437  VLoc = TrackVector.at(x).VLoc;
2438  Utilities->CallLogPop(442);
2439  return true;
2440  }
2441  } // for y....
2442  } // for x...
2443  Utilities->CallLogPop(443);
2444  return false; // all OK
2445 }
2446 
2447 // ---------------------------------------------------------------------------
2448 
2449 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2450 {
2451  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2452  TrackElement.LogTrack(0));
2453  bool FoundFlag;
2454 
2455  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2456  if(FoundFlag)
2457  TrackElement = TrackVector.at(Position);
2458  Utilities->CallLogPop(444);
2459  return FoundFlag;
2460 }
2461 
2462 // ---------------------------------------------------------------------------
2463 
2465 {
2466  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2467  if(NextTrackElementPtr >= TrackVector.end())
2468  {
2469  Utilities->CallLogPop(1336);
2470  return false;
2471  }
2472  Next = *NextTrackElementPtr;
2474  Utilities->CallLogPop(1337);
2475  return true;
2476 }
2477 
2478 // ---------------------------------------------------------------------------
2479 
2481 {
2482  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2484  {
2485  Utilities->CallLogPop(1338);
2486  return false;
2487  }
2488  Next = *NextTrackElementPtr;
2490  Utilities->CallLogPop(1339);
2491  return true;
2492 }
2493 
2494 // ---------------------------------------------------------------------------
2495 
2496 int TTrack::NumberOfGaps(int Caller)
2497 
2498 {
2499  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2500  int Count = 0;
2501 
2502  if(TrackVector.size() == 0)
2503  {
2504  Utilities->CallLogPop(1340);
2505  return 0;
2506  }
2507  for(unsigned int x = 0; x < TrackVector.size(); x++)
2508  {
2509  if(TrackVector.at(x).TrackType == GapJump)
2510  Count++;
2511  }
2512  Utilities->CallLogPop(1341);
2513  return Count;
2514 }
2515 
2516 // ---------------------------------------------------------------------------
2518  // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2519  // returns true for any unset gaps
2520 {
2521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2522  bool UnsetGaps = false;
2523 
2524  if(TrackVector.size() == 0)
2525  {
2526  Utilities->CallLogPop(445);
2527  return false;
2528  }
2529  for(unsigned int x = 0; x < TrackVector.size(); x++)
2530  {
2531  if(TrackVector.at(x).TrackType != GapJump)
2532  {
2533  for(unsigned int y = 0; y < 4; y++)
2534  {
2535  TrackVector.at(x).Conn[y] = -1;
2536  TrackVector.at(x).ConnLinkPos[y] = -1;
2537  }
2538  }
2539  else // GapJump
2540  {
2541 // int tempint = TrackVector.at(x).Conn[0);
2542 
2543  if(TrackVector.at(x).Conn[0] == -1) // unset if -1
2544  {
2545  for(unsigned int y = 0; y < 4; y++)
2546  {
2547  TrackVector.at(x).Conn[y] = -1;
2548  TrackVector.at(x).ConnLinkPos[y] = -1;
2549  }
2550  UnsetGaps = true;
2551  continue; // to next 'x'
2552  }
2553  else // set, but may not have matching element, or that element may not be set
2554  {
2555  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2556  {
2557  TrackVector.at(x).Conn[y] = -1;
2558  TrackVector.at(x).ConnLinkPos[y] = -1;
2559  }
2560 
2561  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
2562  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2563  {
2564  for(unsigned int y = 0; y < 4; y++)
2565  {
2566  TrackVector.at(x).Conn[y] = -1;
2567  TrackVector.at(x).ConnLinkPos[y] = -1;
2568  }
2569  UnsetGaps = true;
2570  continue; // to next 'x'
2571  }
2572 // here if gap connection is itself a GapJump
2573  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
2574  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2575  // if not clear Conns & CLks & reset Lk[0]
2576  {
2577  for(unsigned int y = 0; y < 4; y++)
2578  {
2579  TrackVector.at(x).Conn[y] = -1;
2580  TrackVector.at(x).ConnLinkPos[y] = -1;
2581  }
2582  UnsetGaps = true;
2583  continue; // to next 'x'
2584  }
2585 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2586 // hence no more action needed on these Conns & CLks
2587  }
2588  } // else //gap jump
2589  } // for x...
2590  Utilities->CallLogPop(446);
2591  return UnsetGaps;
2592 }
2593 
2594 // ---------------------------------------------------------------------------
2595 
2596 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2597 {
2598 // VecFile already open and its pointer at right place on calling
2599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2600  int TempInt;
2601 
2602  TrackClear(1);
2603 // load track elements
2604  int NumberOfActiveElements = 0;
2605 
2606  GraphicsFollow = false;
2607  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2608  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2609 
2610  if(MarkerString[MarkerString.Length()] == '1')
2611  {
2612  GraphicsFollow = true;
2613  }
2614  for(int x = 0; x < NumberOfActiveElements; x++)
2615  {
2616  VecFile >> TempInt; // TrackVectorNumber, not used
2617  VecFile >> TempInt; // SpeedTag
2618  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2619  VecFile >> TempInt;
2620  TrackElement.HLoc = TempInt;
2621  VecFile >> TempInt;
2622  TrackElement.VLoc = TempInt;
2623  if(TrackElement.TrackType == GapJump)
2624  {
2625  VecFile >> TempInt;
2626  TrackElement.ConnLinkPos[0] = TempInt;
2627  VecFile >> TempInt;
2628  TrackElement.Conn[0] = TempInt;
2629  }
2630  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2631  {
2632  VecFile >> TempInt;
2633  TrackElement.Attribute = TempInt;
2634  }
2635  if(TrackElement.TrackType == SignalPost)
2636  {
2637  VecFile >> TempInt;
2638  if(TempInt == 0)
2639  TrackElement.CallingOnSet = false;
2640  else
2641  TrackElement.CallingOnSet = true;
2642  }
2643  VecFile >> TempInt;
2644  TrackElement.Length01 = TempInt;
2645  VecFile >> TempInt;
2646  TrackElement.Length23 = TempInt;
2647  VecFile >> TempInt;
2648  if((TempInt != -1) && (TempInt < 10))
2649  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2650  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2651  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2652  TrackElement.SpeedLimit01 = TempInt;
2653  VecFile >> TempInt;
2654  if((TempInt != -1) && (TempInt < 10))
2655  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2656  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2657  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2658  TrackElement.SpeedLimit23 = TempInt;
2659 
2660  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2661  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2662  SetElementID(0, TrackElement);
2663  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2664 // new for v0.6
2665  if(TrackElement.TrackType == SignalPost)
2666  {
2667  if(Marker[1] == '3')
2668  {
2669  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2670  }
2671  else if(Marker[1] == '2')
2672  {
2673  TrackElement.SigAspect = TTrackElement::TwoAspect;
2674  }
2675  else if(Marker[1] == 'G')
2676  {
2677  TrackElement.SigAspect = TTrackElement::GroundSignal;
2678  }
2679  else
2680  {
2681  TrackElement.SigAspect = TTrackElement::FourAspect;
2682  }
2683  }
2684  if(TrackElement.SpeedTag != 0)
2685  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2686  }
2687  int NumberOfInactiveElements = 0;
2688 
2689  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2690  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2691  for(int x = 0; x < NumberOfInactiveElements; x++)
2692  {
2693  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2694  VecFile >> TempInt; // SpeedTag
2695  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2696  VecFile >> TempInt;
2697  TrackElement.HLoc = TempInt;
2698  VecFile >> TempInt;
2699  TrackElement.VLoc = TempInt;
2700  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2701  SetElementID(3, TrackElement);
2702  TrackPush(9, TrackElement);
2703  Utilities->LoadFileString(VecFile); // marker
2704  }
2705  bool LocError = false; // needed for TryToConnectTrack but not used
2706  int H = -1, V = -1; // needed for TryToConnectTrack but not used
2707 
2708  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
2709  {
2710  SetTrackFinished(true);
2711  }
2712  else
2713  {
2714  SetTrackFinished(false);
2715  }
2716 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
2717 // CheckMapAndInactiveTrack(8);
2718 // CheckLocationNameMultiMap(10);
2719  Utilities->CallLogPop(448);
2720 }
2721 
2722 // ---------------------------------------------------------------------------
2723 
2724 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
2725 {
2726 // VecFile already open and its pointer at right place on calling
2727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
2728 // first int is number og graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
2729 // & load into UserGraphicItem then store in UserGraphicVector
2730  UserGraphicVector.clear();
2731  TUserGraphicItem UGI;
2732  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
2733 
2734  for(int x = 0; x < NumberOfGraphics; x++)
2735  {
2736  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
2737  UGI.HPos = Utilities->LoadFileInt(VecFile);
2738  UGI.VPos = Utilities->LoadFileInt(VecFile);
2739  UGI.Width = 0; // provisional value
2740  UGI.Height = 0; // provisional value
2741  UGI.UserGraphic = NULL; // provisional value
2742  UserGraphicVector.push_back(UGI);
2743  }
2744 // now load the map & set Width, Height & TPicture*
2745  bool FileError = false;
2746 
2747  for(int x = 0; x < NumberOfGraphics; x++)
2748  {
2749  if(FileError)
2750  {
2751  break; // otherwise keeps going round the loop
2752  }
2753  UGI = UserGraphicVectorAt(0, x);
2754  if(UserGraphicMap.empty()) // will be when x == 0 but not after
2755  {
2756  try
2757  {
2758 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
2759  UGME.first = UGI.FileName;
2760  UGME.second = new TPicture;
2761  UGME.second->LoadFromFile(UGME.first); // errors caught below
2762  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2763  {
2764  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
2765  }
2766  UGI.UserGraphic = UGME.second;
2767  UGI.Width = UGI.UserGraphic->Width;
2768  UGI.Height = UGI.UserGraphic->Height;
2769  UserGraphicVectorAt(1, x) = UGI;
2770  }
2771  catch(const EInvalidGraphic &e)
2772  {
2773  ShowMessage(UGI.FileName +
2774  " has an incorrect file format, graphics can't be loaded. Ensure that all graphic files are valid with extension .bmp, .gif, .jpg, or .png");
2775  FileError = true;
2776  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2777  if(!UserGraphicMap.empty())
2778  {
2779  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2780  {
2781  delete UGMIt->second;
2782  }
2783  UserGraphicMap.clear();
2784  }
2785  }
2786  catch(const Exception &e)
2787  {
2788  ShowMessage("Unable to load file, ensure that this graphic file exists: " + UGI.FileName +
2789  ", and that it is has extension .bmp, .gif, .jpg, or .png. Graphics can't be loaded.");
2790  FileError = true;
2791  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2792  if(!UserGraphicMap.empty())
2793  {
2794  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2795  {
2796  delete UGMIt->second;
2797  }
2798  UserGraphicMap.clear();
2799  }
2800  }
2801  }
2802  else
2803  {
2804  bool FoundInMap = false;
2805  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2806  {
2807  if(UGI.FileName == UGMIt->first) // already exists in map
2808  {
2809  UGI.UserGraphic = UGMIt->second;
2810  UGI.Width = UGI.UserGraphic->Width;
2811  UGI.Height = UGI.UserGraphic->Height;
2812  UserGraphicVectorAt(2, x) = UGI;
2813  FoundInMap = true;
2814  break;
2815  }
2816  }
2817  if(!FoundInMap)
2818  {
2819  try
2820  {
2822  UGME.first = UGI.FileName;
2823  UGME.second = new TPicture;
2824  UGME.second->LoadFromFile(UGME.first); // errors caught below
2825  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2826  {
2827  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
2828  }
2829  UGI.UserGraphic = UGME.second;
2830  UGI.Width = UGI.UserGraphic->Width;
2831  UGI.Height = UGI.UserGraphic->Height;
2832  UserGraphicVectorAt(3, x) = UGI;
2833  }
2834  catch(const EInvalidGraphic &e)
2835  {
2836  ShowMessage(UGI.FileName +
2837  " has an incorrect file format, graphics can't be loaded. Ensure that all graphic files are valid with extension .bmp, .gif, .jpg, or .png");
2838  FileError = true;
2839  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2840  if(!UserGraphicMap.empty())
2841  {
2842  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2843  {
2844  delete UGMIt->second;
2845  }
2846  UserGraphicMap.clear();
2847  }
2848  }
2849  catch(const Exception &e)
2850  {
2851  ShowMessage("Unable to load file, ensure that this graphic file exists: " + UGI.FileName +
2852  ", and that it is has extension .bmp, .gif, .jpg, or .png");
2853  FileError = true;
2854  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2855  if(!UserGraphicMap.empty())
2856  {
2857  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2858  {
2859  delete UGMIt->second;
2860  }
2861  UserGraphicMap.clear();
2862  }
2863  }
2864  }
2865  }
2866  }
2867  Utilities->CallLogPop(2167);
2868 }
2869 
2870 // ---------------------------------------------------------------------------
2871 
2872 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
2873 {
2874 // VecFile already open and its pointer at right place on calling
2875 // if GraphicsFollow true, then save Marker as **Active elements**1
2876 // save trackfinished flag
2877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
2878  TTrackElement TrackElement, InactiveTrackElement;
2879 
2880 // save track elements
2881  Utilities->SaveFileInt(VecFile, TrackVector.size());
2882  if(GraphicsFollow)
2883  {
2884  VecFile << "**Active elements**1" << '\0' << '\n';
2885  }
2886  else
2887  {
2888  VecFile << "**Active elements**" << '\0' << '\n';
2889  }
2890  for(unsigned int x = 0; x < (TrackVector.size()); x++)
2891  {
2892  TrackElement = TrackVector.at(x);
2893  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
2894  VecFile << TrackElement.SpeedTag << '\n';
2895  VecFile << TrackElement.HLoc << '\n';
2896  VecFile << TrackElement.VLoc << '\n';
2897  if(TrackElement.TrackType == GapJump)
2898  {
2899  VecFile << TrackElement.ConnLinkPos[0] << '\n';
2900  VecFile << TrackElement.Conn[0] << '\n';
2901  }
2902  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2903  {
2904  VecFile << TrackElement.Attribute << '\n';
2905  }
2906  if(TrackElement.TrackType == SignalPost)
2907  {
2908  if(TrackElement.CallingOnSet)
2909  VecFile << int(1) << '\n';
2910  else
2911  VecFile << int(0) << '\n';
2912  }
2913  VecFile << TrackElement.Length01 << '\n';
2914  VecFile << TrackElement.Length23 << '\n';
2915  VecFile << TrackElement.SpeedLimit01 << '\n';
2916  VecFile << TrackElement.SpeedLimit23 << '\n';
2917  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2918  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2919 // new for v0.6
2920  if(TrackElement.TrackType == SignalPost)
2921  {
2922  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
2923  {
2924  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2925  }
2926  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
2927  {
2928  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2929  }
2930  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
2931  {
2932  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2933  }
2934  else // 4 aspect
2935  {
2936  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2937  }
2938  }
2939  else
2940  {
2941  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2942  }
2943  }
2944 
2945  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
2946  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
2947  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
2948  {
2949  InactiveTrackElement = InactiveTrackVector.at(x);
2950  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
2951  VecFile << InactiveTrackElement.SpeedTag << '\n';
2952  VecFile << InactiveTrackElement.HLoc << '\n';
2953  VecFile << InactiveTrackElement.VLoc << '\n';
2954  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2955  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2956  }
2957  Utilities->CallLogPop(449);
2958 }
2959 
2960 // ---------------------------------------------------------------------------
2961 
2962 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
2963 {
2964 // VecFile already open and its pointer at right place on calling
2965 // check trackfinished flag
2966 // inactive elements follow immediately after active elements, no need to check for a marker between them
2967  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
2968  int TempInt;
2969 
2970  GraphicsFollow = false;
2971  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2972  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
2973  {
2974  Utilities->CallLogPop(1513);
2975  return false;
2976  }
2977 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
2978  AnsiString MarkerString;
2979 
2980  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
2981  {
2982  Utilities->CallLogPop(1758);
2983  return false;
2984  }
2985  if(MarkerString[MarkerString.Length()] == '1')
2986  {
2987  GraphicsFollow = true;
2988  }
2989  for(int x = 0; x < NumberOfActiveElements; x++)
2990  {
2991  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
2992  {
2993  Utilities->CallLogPop(1759);
2994  return false;
2995  }
2996  VecFile >> TempInt;
2997  int SpeedTag = TempInt;
2998  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
2999  {
3000  Utilities->CallLogPop(1514);
3001  return false;
3002  }
3003  VecFile >> TempInt;
3004  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3005  {
3006  Utilities->CallLogPop(1495);
3007  return false;
3008  }
3009  VecFile >> TempInt;
3010  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3011  {
3012  Utilities->CallLogPop(1497);
3013  return false;
3014  }
3015  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3016  {
3017  VecFile >> TempInt;
3018  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3019  {
3020  Utilities->CallLogPop(1499);
3021  return false;
3022  }
3023  VecFile >> TempInt;
3024  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3025  {
3026  Utilities->CallLogPop(1500);
3027  return false;
3028  }
3029  }
3030  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3031  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3032  {
3033  VecFile >> TempInt;
3034  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3035  {
3036  Utilities->CallLogPop(1502);
3037  return false;
3038  }
3039  }
3040  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3041  {
3042  VecFile >> TempInt;
3043  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3044  {
3045  Utilities->CallLogPop(1155);
3046  return false;
3047  }
3048  }
3049  VecFile >> TempInt;
3050  if((TempInt < -1) || (TempInt > 999999)) // Length01
3051  {
3052  Utilities->CallLogPop(1503);
3053  return false;
3054  }
3055  VecFile >> TempInt;
3056  if((TempInt < -1) || (TempInt > 999999)) // Length23
3057  {
3058  Utilities->CallLogPop(1504);
3059  return false;
3060  }
3061  VecFile >> TempInt;
3062  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3063  {
3064  Utilities->CallLogPop(1505);
3065  return false;
3066  }
3067  VecFile >> TempInt;
3068  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3069  {
3070  Utilities->CallLogPop(1506);
3071  return false;
3072  }
3073  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3074  {
3075  Utilities->CallLogPop(1142);
3076  return false; // LocationName
3077  }
3078  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3079  {
3080  Utilities->CallLogPop(1143);
3081  return false; // ActiveTrackElementName
3082  }
3083  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3084  {
3085  Utilities->CallLogPop(1787);
3086  return false; // marker
3087  }
3088  }
3089  int NumberOfInactiveElements = 0;
3090 
3091  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3092  if(NumberOfInactiveElements < 0) // No of active elements
3093  {
3094  Utilities->CallLogPop(1493);
3095  return false;
3096  }
3097  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3098  {
3099  Utilities->CallLogPop(1764);
3100  return false; // **Inactive elements** marker
3101  }
3102  for(int x = 0; x < NumberOfInactiveElements; x++)
3103  {
3104  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3105  {
3106  Utilities->CallLogPop(1765);
3107  return false;
3108  }
3109  VecFile >> TempInt;
3110  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3111  {
3112  Utilities->CallLogPop(1494);
3113  return false;
3114  }
3115  VecFile >> TempInt;
3116  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3117  {
3118  Utilities->CallLogPop(1496);
3119  return false;
3120  }
3121  VecFile >> TempInt;
3122  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3123  {
3124  Utilities->CallLogPop(1498);
3125  return false;
3126  }
3127  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3128  {
3129  Utilities->CallLogPop(1144);
3130  return false; // LocationName
3131  }
3132  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3133  {
3134  Utilities->CallLogPop(1788);
3135  return false; // marker
3136  }
3137  }
3138  Utilities->CallLogPop(1507);
3139  return true;
3140 }
3141 
3142 // ---------------------------------------------------------------------------
3143 
3144 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3145 {
3146  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3147  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3148 
3149  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3150  {
3151  Utilities->CallLogPop(2168);
3152  return false;
3153  }
3154  // filename in Graphics folder, then HPos, then VPos
3155  AnsiString FileName;
3156 
3157  for(int x = 0; x < NumberOfGraphics; x++)
3158  {
3159  TPicture *TempPicture = new TPicture;
3160  try
3161  {
3162  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3163  {
3164  Utilities->CallLogPop(2169);
3165  return false;
3166  }
3167  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3168  delete TempPicture;
3169  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3170  {
3171  Utilities->CallLogPop(2170);
3172  return false;
3173  }
3174  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3175  {
3176  Utilities->CallLogPop(2171);
3177  return false;
3178  }
3179  }
3180  catch(const EInvalidGraphic &e)
3181  {
3182  ShowMessage(FileName +
3183  " has an incorrect file format, graphics can't be loaded. Ensure that all graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3184  delete TempPicture;
3185  Utilities->CallLogPop(2172);
3186  return false;
3187  }
3188  catch(const Exception &e)
3189  {
3190  ShowMessage("Unable to load file, ensure that " + FileName +
3191  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3192  delete TempPicture;
3193  Utilities->CallLogPop(2173);
3194  return false;
3195  }
3196  }
3197  Utilities->CallLogPop(2174);
3198  return true;
3199 }
3200 
3201 // ---------------------------------------------------------------------------
3202 
3203 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3204 {
3205  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3206  int VecSize = Track->BarriersDownVector.size();
3207 
3208  Utilities->SaveFileInt(OutFile, VecSize);
3209  for(int x = 0; x < VecSize; x++)
3210  {
3212  Utilities->SaveFileBool(OutFile, TALC.ConsecSignals);
3213  Utilities->SaveFileBool(OutFile, TALC.TrainPassed);
3214  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3215  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3216  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3217  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3218  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3219  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3220  }
3221  Utilities->CallLogPop(1963);
3222 }
3223 
3224 // ---------------------------------------------------------------------------
3225 
3226 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile)
3227 {
3228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3229  int VecSize = Track->ChangingLCVector.size();
3230 
3231  Utilities->SaveFileInt(OutFile, VecSize);
3232  for(int x = 0; x < VecSize; x++)
3233  {
3235  Utilities->SaveFileBool(OutFile, TALC.ConsecSignals);
3236  Utilities->SaveFileBool(OutFile, TALC.TrainPassed);
3237  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3238  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3239  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3240  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3241  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3242  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3243  }
3244  Utilities->CallLogPop(1980);
3245 }
3246 
3247 // ---------------------------------------------------------------------------
3248 
3249 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3250 {
3251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3252  int VecSize = Utilities->LoadFileInt(VecFile);
3253 
3254  for(int x = 0; x < VecSize; x++)
3255  {
3256  if(!Utilities->CheckFileBool(VecFile))
3257  {
3258  Utilities->CallLogPop(1970);
3259  return false;
3260  }
3261  if(!Utilities->CheckFileBool(VecFile))
3262  {
3263  Utilities->CallLogPop(1971);
3264  return false;
3265  }
3266  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3267  {
3268  Utilities->CallLogPop(1972);
3269  return false;
3270  }
3271  if(!Utilities->CheckFileDouble(VecFile))
3272  {
3273  Utilities->CallLogPop(1973);
3274  return false;
3275  }
3276  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3277  {
3278  Utilities->CallLogPop(1974);
3279  return false;
3280  }
3281  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3282  {
3283  Utilities->CallLogPop(1975);
3284  return false;
3285  }
3286  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3287  {
3288  Utilities->CallLogPop(1976);
3289  return false;
3290  }
3291  if(!Utilities->CheckFileDouble(VecFile))
3292  {
3293  Utilities->CallLogPop(1977);
3294  return false;
3295  }
3296  }
3297  Utilities->CallLogPop(1978);
3298  return true;
3299 }
3300 
3301 // ---------------------------------------------------------------------------
3302 
3303 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3304 {
3305  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3306  int VecSize = Utilities->LoadFileInt(VecFile);
3307 
3308  for(int x = 0; x < VecSize; x++)
3309  {
3310  TActiveLevelCrossing TALC;
3311  TALC.ConsecSignals = Utilities->LoadFileBool(VecFile);
3312  TALC.TrainPassed = Utilities->LoadFileBool(VecFile);
3313  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3314  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3315  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3316  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3317  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3318  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3319  BarriersDownVector.push_back(TALC);
3320  }
3321  Utilities->CallLogPop(1979);
3322 }
3323 
3324 // ---------------------------------------------------------------------------
3325 
3326 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3327 /*
3328  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3329  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3330  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3331 */
3332 {
3333  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3334  TTrackElement Next;
3335 
3336 // Disp->ClearDisplay();
3338  while(ReturnNextInactiveTrackElement(0, Next))
3339  {
3340  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3341  {
3342  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3343  {
3344  // only plot if on screen, to save time
3345  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3347  {
3348  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3349  }
3350  }
3351  }
3352  }
3353 
3354  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3355 
3356  NextTrackElementPtr = TrackVector.begin();
3357  while(ReturnNextTrackElement(0, Next))
3358  {
3359  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3360  {
3361  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3363  {
3364  if(Next.TrackType == Points)
3365  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3366  else if(Next.TrackType == SignalPost)
3367  PlotSignal(9, Next, Disp);
3368  else if(Next.TrackType == GapJump)
3369  PlotGap(0, Next, Disp);
3370  else
3371  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3372  }
3373  }
3374  }
3375 
3376  if(BothPointFilletsAndBasicLCs)
3377  {
3379  while(ReturnNextInactiveTrackElement(4, Next))
3380  {
3381  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3382  {
3383  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3384  {
3385  // only plot if on screen, to save time, & OK as plotting one by one here
3386  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3388  {
3389  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3390  {
3391  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3392  }
3393  else
3394  {
3395  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3396  }
3397  }
3398  }
3399  }
3400  }
3401  }
3402  Disp->Update();
3403  Utilities->CallLogPop(468);
3404 }
3405 
3406 // ---------------------------------------------------------------------------
3407 
3408 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3409 {
3410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3411  if(UserGraphicVector.empty())
3412  {
3413  Utilities->CallLogPop(2175);
3414  return;
3415  }
3416  TUserGraphicItem UGI;
3417 
3418  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3419  {
3420  UGI = UserGraphicVectorAt(4, x);
3421  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3422  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3423  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3424  {
3425  Disp->PlotAndAddUserGraphic(0, UGI);
3426  }
3427  }
3428  Disp->Update();
3429  Utilities->CallLogPop(2176);
3430 }
3431 
3432 // ---------------------------------------------------------------------------
3433 
3434 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3435 /*
3436  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3437 */
3438 {
3439  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3440 // need to change graphics back to black on white if have a dark background
3441  TColor OldTransparentColour = Utilities->clTransparent;
3442 
3444  {
3445  Utilities->clTransparent = TColor(0xFFFFFF); // white
3448  }
3449  TTrackElement Next;
3450 
3451  Bitmap->Canvas->CopyMode = cmSrcCopy;
3453  Graphics::TBitmap *GraphicOutput;
3454 
3455  while(ReturnNextInactiveTrackElement(2, Next))
3456  {
3457  GraphicOutput = Next.GraphicPtr;
3458  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3459  {
3460  if(Next.LocationName == "") // plot as named or unnamed (striped)
3461  { // default is not striped
3462  switch(Next.SpeedTag)
3463  {
3464  case 76: // t platform
3465  GraphicOutput = RailGraphics->gl76Striped;
3466  break;
3467 
3468  case 77: // h platform
3469  GraphicOutput = RailGraphics->bm77Striped;
3470  break;
3471 
3472  case 78: // v platform
3473  GraphicOutput = RailGraphics->bm78Striped;
3474  break;
3475 
3476  case 79: // r platform
3477  GraphicOutput = RailGraphics->gl79Striped;
3478  break;
3479 
3480  case 96: // concourse
3481  GraphicOutput = RailGraphics->ConcourseStriped;
3482  break;
3483 
3484  case 129: // v footbridge
3485  GraphicOutput = RailGraphics->gl129Striped;
3486  break;
3487 
3488  case 130: // h footbridge
3489  GraphicOutput = RailGraphics->gl130Striped;
3490  break;
3491 
3492  case 131: // non-station named loc
3493  GraphicOutput = RailGraphics->bmNameStriped;
3494  break;
3495 
3496  case 145: // v underpass
3497  GraphicOutput = RailGraphics->gl145Striped;
3498  break;
3499 
3500  case 146: // h underpass
3501  GraphicOutput = RailGraphics->gl146Striped;
3502  break;
3503 
3504  default:
3505  GraphicOutput = Next.GraphicPtr;
3506  break;
3507  }
3508  }
3509  if(Next.SpeedTag == 144) // level crossing
3510  {
3511  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3512  {
3513  GraphicOutput = RailGraphics->LCBothVer;
3514  }
3515  else
3516  {
3517  GraphicOutput = RailGraphics->LCBothHor;
3518  }
3519  }
3520  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3521  }
3522  }
3523 
3524  NextTrackElementPtr = TrackVector.begin();
3525  while(ReturnNextTrackElement(2, Next))
3526  {
3527  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3528  {
3529  if(Next.TrackType == Points) // plot both fillets
3530  {
3531  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3532  if(Next.SpeedTag < 28)
3533  {
3534  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3536  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3538  }
3539  else if(Next.SpeedTag < 132)
3540  {
3541  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3542  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3543  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3544  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3545  }
3546  else
3547  {
3548  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3549  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3550  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3551  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3552  }
3553  }
3554  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3555  {
3556  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3557  {
3558  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3559  }
3560  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3561  {
3562  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3563  }
3564  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3565  {
3566  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3567  }
3568  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3569  {
3570  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3571  }
3572  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3573  {
3574  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3575  }
3576  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3577  {
3578  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3579  }
3580  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3581  {
3582  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3583  }
3584  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3585  {
3586  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3587  }
3588  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3589  {
3590  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3591  }
3592  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3593  {
3594  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3595  }
3596  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3597  {
3598  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3599  }
3600  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3601  {
3602  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3603  }
3604  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3605  {
3606  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3607  }
3608  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3609  {
3610  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3611  }
3612  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3613  {
3614  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3615  }
3616  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3617  {
3618  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3619  }
3620  }
3621  // below added for version 0.6, only stop signals to be drawn
3622  else if(Next.TrackType == SignalPost)
3623  {
3624  for(int x = 0; x < 40; x++)
3625  {
3626  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3627  {
3628  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3629  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3630  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3631  int HOffset = 0;
3632  if(Next.SpeedTag > 73)
3633  HOffset = 5;
3634  else if(Next.SpeedTag == 71)
3635  HOffset = 9;
3636  int VOffset = 0;
3637  if(Next.SpeedTag == 69)
3638  VOffset = 9;
3639  else if(Next.SpeedTag == 72)
3640  VOffset = 5;
3641  else if(Next.SpeedTag == 74)
3642  VOffset = 5;
3643  Graphics::TBitmap *GraphicPtr;
3644  if(Next.SpeedTag > 71)
3645  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3646  else if(Next.SpeedTag < 70)
3647  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3648  else
3649  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3650  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3651  // plot special signal platform if present
3652  Graphics::TBitmap* SignalPlatformGraphic;
3653  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
3654  {
3655  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3656  }
3657  // now plot signal (double yellow overwrites most of signal platform if present)
3658  // below amended for version 0.6
3660  {
3661  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3662  }
3663  else if(Next.SigAspect == TTrackElement::TwoAspect)
3664  {
3665  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3666  }
3667  else if(Next.SigAspect == TTrackElement::GroundSignal)
3668  {
3669  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3670  }
3671  else // 4 aspect
3672  {
3673  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3674  }
3675  break;
3676  }
3677  }
3678  }
3679  else
3680  {
3681  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3682  }
3683  }
3684  }
3685  if(OldTransparentColour != clB5G5R5)
3686  {
3687  Utilities->clTransparent = OldTransparentColour; // restore
3690  }
3691  Utilities->CallLogPop(1533);
3692 }
3693 
3694 // ---------------------------------------------------------------------------
3695 
3696 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
3697 {
3698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
3699  if(UserGraphicVector.empty())
3700  {
3701  Utilities->CallLogPop(2192);
3702  return;
3703  }
3704  else
3705  {
3706  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3707  {
3708  Bitmap->Canvas->CopyMode = cmSrcCopy;
3709  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
3710  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
3711  }
3712  }
3713  Utilities->CallLogPop(2193);
3714 }
3715 
3716 // ---------------------------------------------------------------------------
3717 
3718 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3719 /*
3720  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3721  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
3722 */
3723 {
3724  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
3725 // need to change graphics back to black on white if have a dark background
3726  TColor OldTransparentColour = Utilities->clTransparent;
3727 
3729  {
3730  Utilities->clTransparent = TColor(0xFFFFFF); // white
3733  }
3734  TTrackElement Next;
3735 
3736  Bitmap->Canvas->CopyMode = cmSrcCopy;
3738  Graphics::TBitmap *GraphicOutput;
3739 
3740  while(ReturnNextInactiveTrackElement(3, Next))
3741  {
3742  GraphicOutput = Next.GraphicPtr; // no striped name graphics
3743  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3744  {
3745  if(Next.SpeedTag == 144) // level crossing
3746  {
3747  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
3748  if(BaseElement == 1) // hor element
3749  {
3750  if(Next.Attribute == 1) // open to trains
3751  {
3752  GraphicOutput = RailGraphics->LCBothHor;
3753  }
3754  else // plot as closed to trains if in any other state
3755  {
3756  GraphicOutput = RailGraphics->LCBothVer;
3757  }
3758  }
3759  else // vert element
3760  {
3761  if(Next.Attribute == 1) // open to trains
3762  {
3763  GraphicOutput = RailGraphics->LCBothVer;
3764  }
3765  else // plot as closed to trains if in any other state
3766  {
3767  GraphicOutput = RailGraphics->LCBothHor;
3768  }
3769  }
3770  }
3771  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3772  }
3773  }
3774 
3775  NextTrackElementPtr = TrackVector.begin();
3776  while(ReturnNextTrackElement(3, Next))
3777  {
3778  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3779  {
3780  if(Next.TrackType == Points) // plot active fillet
3781  {
3782  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3783  if(Next.SpeedTag < 28)
3784  {
3785  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3787  }
3788  else if(Next.SpeedTag < 132)
3789  {
3790  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3792  }
3793  else
3794  {
3795  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3797  }
3798  }
3799  else if(Next.TrackType == GapJump) // plot as connected
3800  {
3801  if(Next.SpeedTag == 88)
3802  {
3803  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3804  }
3805  else if(Next.SpeedTag == 89)
3806  {
3807  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3808  }
3809  else if(Next.SpeedTag == 90)
3810  {
3811  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3812  }
3813  else if(Next.SpeedTag == 91)
3814  {
3815  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3816  }
3817  else if(Next.SpeedTag == 92)
3818  {
3819  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3820  }
3821  else if(Next.SpeedTag == 93)
3822  {
3823  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3824  }
3825  else if(Next.SpeedTag == 94)
3826  {
3827  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3828  }
3829  else if(Next.SpeedTag == 95)
3830  {
3831  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3832  }
3833  }
3834  else if(Next.TrackType == SignalPost) // plot in correct colour
3835  {
3836  for(int x = 0; x < 40; x++)
3837  {
3838  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
3839  {
3840  // plot blank first, then plot platform if present - (always not striped for operating railway)
3841  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3842  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3843  int HOffset = 0;
3844  if(Next.SpeedTag > 73)
3845  HOffset = 5;
3846  else if(Next.SpeedTag == 71)
3847  HOffset = 9;
3848  int VOffset = 0;
3849  if(Next.SpeedTag == 69)
3850  VOffset = 9;
3851  else if(Next.SpeedTag == 72)
3852  VOffset = 5;
3853  else if(Next.SpeedTag == 74)
3854  VOffset = 5;
3855  Graphics::TBitmap *GraphicPtr;
3856  if(Next.SpeedTag > 71)
3857  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3858  else if(Next.SpeedTag < 70)
3859  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3860  else
3861  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3862  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3863  // plot special signal platform if present
3864  Graphics::TBitmap* SignalPlatformGraphic;
3865  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3866  {
3867  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3868  }
3869  // now plot signal (double yellow overwrites most of signal platform if present)
3870  // below amended for version 0.6
3872  {
3873  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3874  }
3875  else if(Next.SigAspect == TTrackElement::TwoAspect)
3876  {
3877  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3878  }
3879  else if(Next.SigAspect == TTrackElement::GroundSignal)
3880  {
3881  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3882  }
3883  else // 4 aspect
3884  {
3885  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3886  }
3887  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
3888  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
3889  {
3890  if(Next.SpeedTag == 68)
3891  {
3892  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
3893  }
3894  if(Next.SpeedTag == 69)
3895  {
3896  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
3897  }
3898  if(Next.SpeedTag == 70)
3899  {
3900  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
3901  }
3902  if(Next.SpeedTag == 71)
3903  {
3904  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
3905  }
3906  if(Next.SpeedTag == 72)
3907  {
3908  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
3909  }
3910  if(Next.SpeedTag == 73)
3911  {
3912  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
3913  }
3914  if(Next.SpeedTag == 74)
3915  {
3916  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
3917  }
3918  if(Next.SpeedTag == 75)
3919  {
3920  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
3921  }
3922  }
3923  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
3924  {
3925  for(int x = 0; x < 40; x++)
3926  {
3927  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
3928  {
3929  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3930  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
3931  Utilities->RHSignalFlag); // in case existing signal is a double yellow
3932  // plot special signal platform if present
3933  Graphics::TBitmap* SignalPlatformGraphic;
3934  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3935  {
3936  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3937  }
3938  // now plot signal
3939  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3940  break;
3941  }
3942  }
3943  }
3944  break;
3945  }
3946  }
3947  }
3948  else
3949  {
3950  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3951  }
3952  }
3953  }
3954  if(OldTransparentColour != clB5G5R5)
3955  {
3956  Utilities->clTransparent = OldTransparentColour; // restore
3959  }
3960  Utilities->CallLogPop(1701);
3961 }
3962 
3963 // ---------------------------------------------------------------------------
3964 
3965 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
3966 {
3967  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
3968  for(unsigned int x = 0; x < TrackVector.size(); x++)
3969  {
3970  if(TrackVector.at(x).TrackType == GapJump)
3971  {
3972  if(TrackVector.at(x).Conn[0] > -1)
3973  continue; // to next 'x' value as this element has already been set
3974  // here if identify a GapJump element not yet set
3975  GapPos = x;
3976  GapHLoc = TrackVector.at(x).HLoc;
3977  GapVLoc = TrackVector.at(x).VLoc;
3978  // highlight it
3980  Utilities->CallLogPop(469);
3981  return true;
3982  }
3983  }
3984  Utilities->CallLogPop(470);
3985  return false;
3986 }
3987 
3988 // ---------------------------------------------------------------------------
3989 
3990 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
3991 {
3992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
3993  AnsiString(VLoc));
3994  int Position;
3995  TTrackElement TrackElement;
3996 
3997  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
3998  {
3999  Utilities->CallLogPop(471);
4000  return false; // not found
4001  }
4002  if(TrackElement.TrackType != GapJump)
4003  {
4004  Utilities->CallLogPop(472);
4005  return false; // found something but not a gap
4006  }
4007  if(Position == GapPos)
4008  {
4009  Utilities->CallLogPop(473);
4010  return false; // selected original gap
4011  }
4012  if(TrackVector.at(Position).Conn[0] != -1)
4013  {
4014  Utilities->CallLogPop(474);
4015  return false; // already selected
4016  }
4017  TrackVector.at(Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4018  TrackVector.at(Position).ConnLinkPos[0] = 0;
4019  TrackVector.at(GapPos).Conn[0] = Position; // set other one similarly
4020  TrackVector.at(GapPos).ConnLinkPos[0] = 0;
4021 // now highlight the selected location
4022  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4023  Utilities->CallLogPop(475);
4024  return true;
4025 }
4026 
4027 // ---------------------------------------------------------------------------
4028 
4029 bool TTrack::GapsUnset(int Caller)
4030  // returns true if there are gaps and any are unset
4031 {
4032  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4033  if(TrackVector.size() == 0)
4034  {
4035  Utilities->CallLogPop(476);
4036  return false;
4037  }
4038  for(unsigned int x = 0; x < TrackVector.size(); x++)
4039  {
4040  if(TrackVector.at(x).TrackType == GapJump)
4041  {
4042  if(TrackVector.at(x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4043  {
4044  Utilities->CallLogPop(477);
4045  return true;
4046  }
4047  else // set, but may not have matching element, or that element may not be set
4048  {
4049  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4050  // check that the element pointed to by the gap link is a GapJump
4051  {
4052  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4053  Utilities->CallLogPop(1137);
4054  return false;
4055  }
4056 // here if gap connection is itself a GapJump
4057  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4058  // check that the element pointed to by the gap link is a GapJump & that its gap link
4059  // points back to 'x'
4060  {
4061  Utilities->CallLogPop(478);
4062  return true;
4063  }
4064 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4065  }
4066  } // if(TrackVector.at(x).TrackType == GapJump)
4067  } // for x...
4068  Utilities->CallLogPop(479);
4069  return false;
4070 }
4071 
4072 // ---------------------------------------------------------------------------
4073 
4074 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4075 {
4076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4077  for(unsigned int x = 0; x < TrackVector.size(); x++)
4078  {
4079  if(TrackVector.at(x).TrackType == GapJump)
4080  {
4081  Utilities->CallLogPop(1105);
4082  return false;
4083  }
4084  }
4085  Utilities->CallLogPop(1106);
4086  return true;
4087 }
4088 
4089 // ---------------------------------------------------------------------------
4090 
4091 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4092 {
4093  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4094  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4095  {
4096  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4097  {
4098  Utilities->CallLogPop(1107);
4099  return false;
4100  }
4101  }
4102  for(unsigned int x = 0; x < TrackVector.size(); x++)
4103  {
4104  if(TrackVector.at(x).FixedNamedLocationElement)
4105  {
4106  Utilities->CallLogPop(1108);
4107  return false;
4108  }
4109  }
4110  Utilities->CallLogPop(1109);
4111  return true;
4112 }
4113 
4114 // ---------------------------------------------------------------------------
4115 
4117  // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4118  // returns false otherwise or if there are no NamedLocationElements
4119 {
4120  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4121  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4122  {
4123  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4124  {
4125  if(InactiveTrackVector.at(x).LocationName == "")
4126  {
4127  Utilities->CallLogPop(1110);
4128  return true;
4129  }
4130  }
4131  }
4132  for(unsigned int x = 0; x < TrackVector.size(); x++)
4133  {
4134  if(TrackVector.at(x).FixedNamedLocationElement)
4135  {
4136  if(TrackVector.at(x).LocationName == "")
4137  {
4138  Utilities->CallLogPop(1111);
4139  return true;
4140  }
4141  }
4142  }
4143  Utilities->CallLogPop(1112);
4144  return false;
4145 }
4146 
4147 // ---------------------------------------------------------------------------
4148 
4149 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4150 {
4151  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4152  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4153  Utilities->CallLogPop(480);
4154 }
4155 
4156 // ---------------------------------------------------------------------------
4157 
4159 {
4160  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4161  if(TrackVector.size() == 0)
4162  {
4163  Utilities->CallLogPop(481);
4164  return;
4165  }
4166  for(unsigned int x = 0; x < TrackVector.size(); x++)
4167  {
4168  if(TrackVector.at(x).TrackType == GapJump)
4169  {
4170  if(TrackVector.at(x).Conn[0] > -1) // set
4171  {
4172  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4173  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4174  {
4175  TrackVector.at(x).Conn[0] = -1;
4176  TrackVector.at(x).ConnLinkPos[0] = -1;
4177  continue; // to next 'x'
4178  }
4179 // here if gap connection is itself a GapJump
4180  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4181  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4182  // if not clear Conns & CLks
4183  {
4184  TrackVector.at(x).Conn[0] = -1;
4185  TrackVector.at(x).ConnLinkPos[0] = -1;
4186  continue; // to next 'x'
4187  }
4188 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4189 // hence no more action needed on these Conns & CLks
4190  }
4191  } // else //gap jump
4192  } // for x...
4193 // throw Exception("Test Exception");//test
4194  Utilities->CallLogPop(482);
4195 }
4196 
4197 // ---------------------------------------------------------------------------
4198 
4199 void TTrack::ResetSignals(int Caller)
4200 {
4201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4202  for(unsigned int x = 0; x < TrackVector.size(); x++)
4203  {
4204  if(TrackVector.at(x).TrackType == SignalPost)
4205  {
4206  TrackVector.at(x).Attribute = 0;
4207  }
4208  }
4209  Utilities->CallLogPop(483);
4210 }
4211 
4212 // ---------------------------------------------------------------------------
4213 
4214 void TTrack::ResetPoints(int Caller)
4215 {
4216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4217  for(unsigned int x = 0; x < TrackVector.size(); x++)
4218  {
4219  if(TrackVector.at(x).TrackType == Points)
4220  {
4221  TrackVector.at(x).Attribute = 0;
4222  }
4223  }
4224  Utilities->CallLogPop(484);
4225 }
4226 
4227 // ---------------------------------------------------------------------------
4228 
4229 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4230 {
4231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4232  if(TrackVector.empty())
4233  {
4234  TrackMap.clear();
4235  Utilities->CallLogPop(485);
4236  return true;
4237  }
4238 
4239 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4240  THVPair TrackMapKeyPair;
4241 
4242  NewVector.clear();
4243  TTrackMapIterator TrackMapPtr;
4244 
4245  if(!TrackMap.empty())
4246  {
4247  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4248  {
4249  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4250  }
4251  }
4252  if(NewVector.size() != TrackMap.size())
4253  {
4254  throw Exception("Error - Map & Vector different sizes");
4255  }
4256  unsigned int NonZeroCount = 0;
4257 
4258  for(unsigned int x = 0; x < TrackVector.size(); x++)
4259  {
4260  if(TrackVector.at(x).TrackType != Erase)
4261  NonZeroCount++;
4262  }
4263  if(NewVector.size() != NonZeroCount)
4264  {
4265  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4266  }
4267 
4269  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4270  TTrackMapEntry TrackMapEntry;
4271 
4272  for(unsigned int x = 0; x < TrackVector.size(); x++)
4273  {
4274  TrackMapKeyPair.first = TrackVector.at(x).HLoc;
4275  TrackMapKeyPair.second = TrackVector.at(x).VLoc;
4276  TrackMapEntry.first = TrackMapKeyPair;
4277  TrackMapEntry.second = x;
4278  if(!(TrackMap.insert(TrackMapEntry).second))
4279  {
4280  throw Exception("Error - map insertion failure, TrackVector in error");
4281  }
4282  }
4283 // All track now relocated in TrackVector, reset all Conns & CLks
4284  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4285  {
4286  for(unsigned int y = 0; y < 4; y++)
4287  {
4288  TrackVector.at(x).Conn[y] = -1;
4289  TrackVector.at(x).ConnLinkPos[y] = -1;
4290  }
4291  }
4292  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4293  CheckMapAndTrack(4); // test
4294  CheckMapAndInactiveTrack(4); // test
4295  CheckLocationNameMultiMap(8); // test
4296  if(!ResetGapsFromGapMap(1))
4297  {
4298  Utilities->CallLogPop(489);
4299  return false;
4300  }
4301  Utilities->CallLogPop(490);
4302  return true;
4303 }
4304 
4305 // ---------------------------------------------------------------------------
4306 
4307 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4308 {
4309  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4310  GapMap.clear();
4311  THVPair GapMapKeyPair, GapMapValuePair;
4312  TGapMapEntry GapMapEntry;
4313 
4314  for(unsigned int x = 0; x < TrackVector.size(); x++)
4315  {
4316  if(TrackVector.at(x).TrackType == GapJump)
4317  {
4318  GapMapKeyPair.first = TrackVector.at(x).HLoc;
4319  GapMapKeyPair.second = TrackVector.at(x).VLoc;
4320  GapMapEntry.first = GapMapKeyPair;
4321  if(TrackVector.at(x).Conn[0] == -1)
4322  {
4323  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4324  }
4325  GapMapValuePair.first = TrackElementAt(7, TrackVector.at(x).Conn[0]).HLoc;
4326  GapMapValuePair.second = TrackElementAt(8, TrackVector.at(x).Conn[0]).VLoc;
4327  GapMapEntry.second = GapMapValuePair;
4328  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4329  {
4330  GapMap.insert(GapMapEntry);
4331  }
4332  }
4333  }
4334  Utilities->CallLogPop(492);
4335 }
4336 
4337 // ---------------------------------------------------------------------------
4338 
4339 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4340 {
4341  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4342  LocError = false;
4343  bool CheckForLinks = false;
4344 
4345  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4346  {
4347  if(TrackVector.at(x).TrackType == Erase) //Erase isn't used any more as a track type
4348  continue; // skip blank elements
4349 // check footcrossing linkages
4350  if(TrackVector.at(x).TrackType == FootCrossing)
4351  {
4352  if(!CheckFootCrossingLinks(1, TrackVector.at(x)))
4353  {
4354  ShowMessage(
4355  "Footbridge or underpass connection error. Each end must connect to a platform, concourse or other footbridge or underpass, and they can't connect to each other");
4356  HLoc = TrackVector.at(x).HLoc;
4357  VLoc = TrackVector.at(x).VLoc;
4358  LocError = true;
4359  Utilities->CallLogPop(493);
4360  return false;
4361  }
4362  }
4363  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4364  {
4365  CheckForLinks = false;
4366  if(TrackVector.at(x).Link[y] <= 0)
4367  continue; // no link
4368  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4369  continue; // buffer
4370  if(TrackVector.at(x).Config[y] == Gap)
4371  continue; // gaps set later from GapMap
4372 
4373  // get required H & V for track element joining link 'y'
4374  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4375  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4376  // find track element if present
4377  bool ConnectionFoundFlag;
4378  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4379  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4380  {
4381  ShowMessage("Can't have a track element adjacent to a continuation exit");
4382  HLoc = TrackVector.at(x).HLoc;
4383  VLoc = TrackVector.at(x).VLoc;
4384  LocError = true;
4385  if(FinalCall)
4386  {
4387  throw Exception("Error in final track linkage - continuation adjacent to another element");
4388  }
4389  Utilities->CallLogPop(1539);
4390  return false;
4391  }
4392  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4393  continue;
4394  if(ConnectionFoundFlag)
4395  {
4396  TrackVector.at(x).Conn[y] = VecPos;
4397  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4398  bool LinkFoundFlag = false;
4399  if((TrackVector.at(x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4400  { // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4401  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4402  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4403  }
4404  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover))
4405  && (TrackVector.at(VecPos).TrackType == Buffers))
4406  {
4407  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4408  // need room for a train (2 elements) without fouling points or signals
4409  }
4410  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4411  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4412  {
4413  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4414  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4415  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4416  // be named but needs the adjacent element named too
4417  }
4418  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4419  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4420  {
4421  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4422  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4423  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4424  }
4425  else if((TrackVector.at(x).Config[y] == Signal) && (TrackVector.at(VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4426  {
4427  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message won't be shown again.");
4428  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4429  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4430  }
4431  else if(IsLCAtHV(45, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(46, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4432  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4433  {
4434  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4435  }
4436  else
4437  CheckForLinks = true;
4438  if(CheckForLinks)
4439  {
4440  for(unsigned int a = 0; a < 4; a++)
4441  {
4442  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4443  (TrackVector.at(VecPos).Config[a] != Gap))
4444  {
4445  TrackVector.at(x).ConnLinkPos[y] = a;
4446  // note - this ensures that if the connecting element is a leading point
4447  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4448  // (Points have the same link value for both [0] and [2])
4449  LinkFoundFlag = true;
4450  break; // stop after first find or will find later link for leading point
4451  }
4452  }
4453  }
4454  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4455  if(!LinkFoundFlag)
4456  {
4457  HLoc = TrackVector.at(x).HLoc;
4458  VLoc = TrackVector.at(x).VLoc;
4459  LocError = true;
4460  if(FinalCall)
4461  {
4462  throw Exception("Error in final track linkage - invalid link");
4463  }
4464  Utilities->CallLogPop(494);
4465  return false;
4466  }
4467  }
4468  // if there isn't a connection set the invert values for the offending element
4469  else // if(ConnectionFoundFlag)
4470  {
4471  HLoc = TrackVector.at(x).HLoc;
4472  VLoc = TrackVector.at(x).VLoc;
4473  LocError = true;
4474  if(FinalCall)
4475  {
4476  throw Exception("Error in final track linkage - connection not found");
4477  }
4478  Utilities->CallLogPop(495);
4479  return false;
4480  }
4481  }
4482  } // for(unsigned int x=0;x<TrackVector.size();x++)
4483 
4484  if(FinalCall)
4486 
4487 // final check
4488  bool ConnErrorFlag = false;
4489 
4490  for(unsigned int x = 0; x < TrackVector.size(); x++)
4491  {
4492  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4493  ConnErrorFlag = true;
4494  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4495  ConnErrorFlag = true;
4496  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4497  ConnErrorFlag = true;
4498  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4499  ConnErrorFlag = true;
4500  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4501  {
4502  if(TrackVector.at(x).ActiveTrackElementName == "")
4503  {
4504  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4505  {
4506  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4507  }
4508  }
4509  }
4510  }
4511  if(ConnErrorFlag)
4512  {
4513  if(FinalCall)
4514  {
4515  throw Exception("ConnError in LinkTrack - Final");
4516  }
4517  else
4518  {
4519  throw Exception("ConnError in LinkTrack - Precheck");
4520  }
4521  }
4522 
4523  bool CLkErrorFlag = false;
4524 
4525  for(unsigned int x = 0; x < TrackVector.size(); x++)
4526  {
4527  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4528  CLkErrorFlag = true;
4529  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4530  CLkErrorFlag = true;
4531  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4532  CLkErrorFlag = true;
4533  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4534  CLkErrorFlag = true;
4535  }
4536 
4537  if(CLkErrorFlag)
4538  {
4539  if(FinalCall)
4540  {
4541  throw Exception("CLkError in LinkTrack - Final");
4542  }
4543  else
4544  {
4545  throw Exception("CLkError in LinkTrack - Precheck");
4546  }
4547  }
4548 
4549 // set element lengths to min of 20m
4550  for(unsigned int x = 0; x < TrackVector.size(); x++)
4551  {
4552  if(TrackVector.at(x).TrackType == Erase)
4553  continue; // skip blank elements
4554  if(TrackVector.at(x).Length01 < 20)
4555  TrackVector.at(x).Length01 = 20;
4556  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4557  TrackVector.at(x).Length23 = 20;
4558  }
4559 
4560  if(FinalCall) // ONLY at FinalCall, no point calling twice
4561  {
4562  CalcHLocMinEtc(3);
4563  }
4564  Utilities->CallLogPop(497);
4565  return true;
4566 }
4567 
4568 // ---------------------------------------------------------------------------
4569 
4570 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4571 {
4572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4573  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4574  {
4575  if(TrackVector.at(x).TrackType == Erase)
4576  continue; // skip blank elements
4577 
4578 // check footcrossing linkages
4579  if(TrackVector.at(x).TrackType == FootCrossing)
4580  {
4581  if(!CheckFootCrossingLinks(3, TrackVector.at(x)))
4582  {
4583  Utilities->CallLogPop(1127);
4584  return false;
4585  }
4586  }
4587 
4588  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4589  {
4590  if(TrackVector.at(x).Link[y] <= 0)
4591  continue; // no link
4592  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4593  continue; // buffer
4594  if(TrackVector.at(x).Config[y] == Gap)
4595  continue; // gaps set later from GapMap
4596 
4597  // get required H & V for track element joining link 'y'
4598  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4599  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4600  // find track element if present
4601  bool ConnectionFoundFlag;
4602  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
4603  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4604  {
4605  if(FinalCall)
4606  {
4607  throw Exception("Error in final track linkage - continuation adjacent to another element");
4608  }
4609  Utilities->CallLogPop(1540);
4610  return false;
4611  }
4612  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4613  continue;
4614  if(ConnectionFoundFlag)
4615  {
4616  TrackVector.at(x).Conn[y] = VecPos;
4617  bool LinkFoundFlag = false;
4618  // find connecting link in the newly found track element if there is one & make checks
4619  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4620  (TrackVector.at(VecPos).TrackType == Buffers))
4621  {
4622  Utilities->CallLogPop(1541);
4623  return false;
4624  }
4625  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4626  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4627  {
4628  Utilities->CallLogPop(1542);
4629  return false;
4630  }
4631  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4632  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4633  {
4634  Utilities->CallLogPop(1543);
4635  return false;
4636  }
4637  else if(IsLCAtHV(47, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(48, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4638  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4639  {
4640  Utilities->CallLogPop(1981);
4641  return false;
4642  }
4643 /* remove this restriction now that not permitted to treat a named continuation as a location stop
4644  else if(TrackVector.at(x).TrackType == Continuation)
4645  {
4646  int H = TrackVector.at(x).HLoc;
4647  int V = TrackVector.at(x).VLoc;
4648  bool FoundFlag = false;
4649  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
4650  if(FoundFlag)
4651  {
4652  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
4653  {
4654  int NewH = TrackElementAt(727, (TrackVector.at(x).Conn[1])).HLoc;
4655  int NewV = TrackElementAt(728, (TrackVector.at(x).Conn[1])).VLoc;
4656  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
4657  if(FoundFlag)
4658  {
4659  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
4660  {
4661  Utilities->CallLogPop(1544);
4662  return false;
4663  }
4664  }
4665  else
4666  {
4667  Utilities->CallLogPop(1545);
4668  return false;
4669  }
4670  }
4671  }
4672  }
4673 */
4674  for(unsigned int a = 0; a < 4; a++)
4675  {
4676  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4677  (TrackVector.at(VecPos).Config[a] != Gap))
4678  {
4679  TrackVector.at(x).ConnLinkPos[y] = a;
4680  // note - this ensures that if the connecting element is a leading point
4681  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4682  // (Points have the same link value for both [0] and [2])
4683  LinkFoundFlag = true;
4684  break; // stop after first find or will find later link for leading point
4685  }
4686  }
4687  if(!LinkFoundFlag)
4688  {
4689  if(FinalCall)
4690  {
4691  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
4692  }
4693  Utilities->CallLogPop(1128);
4694  return false;
4695  }
4696  }
4697  else // if(ConnectionFoundFlag)
4698  {
4699  if(FinalCall)
4700  {
4701  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
4702  }
4703  Utilities->CallLogPop(1129);
4704  return false;
4705  }
4706  }
4707  } // for(unsigned int x=0;x<TrackVector.size();x++)
4708 
4709  if(FinalCall)
4711 
4712 // final check
4713  bool ConnErrorFlag = false;
4714 
4715  for(unsigned int x = 0; x < TrackVector.size(); x++)
4716  {
4717  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4718  ConnErrorFlag = true;
4719  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4720  ConnErrorFlag = true;
4721  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4722  ConnErrorFlag = true;
4723  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4724  ConnErrorFlag = true;
4725  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4726  {
4727  if(TrackVector.at(x).ActiveTrackElementName == "")
4728  {
4729  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4730  {
4731  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4732  }
4733  }
4734  }
4735  }
4736  if(ConnErrorFlag)
4737  {
4738  if(FinalCall)
4739  {
4740  throw Exception("ConnError in LinkTrack - Final");
4741  }
4742  else
4743  {
4744  throw Exception("ConnError in LinkTrack - Precheck");
4745  }
4746  }
4747 
4748  bool CLkErrorFlag = false;
4749 
4750  for(unsigned int x = 0; x < TrackVector.size(); x++)
4751  {
4752  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4753  CLkErrorFlag = true;
4754  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4755  CLkErrorFlag = true;
4756  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4757  CLkErrorFlag = true;
4758  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4759  CLkErrorFlag = true;
4760  }
4761 
4762  if(CLkErrorFlag)
4763  {
4764  if(FinalCall)
4765  {
4766  throw Exception("CLkError in LinkTrack - Final");
4767  }
4768  else
4769  {
4770  throw Exception("CLkError in LinkTrack - Precheck");
4771  }
4772  }
4773 
4774 // set element lengths to min of 20m
4775  for(unsigned int x = 0; x < TrackVector.size(); x++)
4776  {
4777  if(TrackVector.at(x).TrackType == Erase)
4778  continue; // skip blank elements
4779  if(TrackVector.at(x).Length01 < 20)
4780  TrackVector.at(x).Length01 = 20;
4781  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4782  TrackVector.at(x).Length23 = 20;
4783  }
4784 
4785  if(FinalCall) // ONLY at FinalCall, no point calling twice
4786  {
4787  CalcHLocMinEtc(7);
4788  }
4789  Utilities->CallLogPop(1130);
4790  return true;
4791 }
4792 
4793 // ---------------------------------------------------------------------------
4794 
4795 bool TTrack::IsTrackLinked(int Caller) // not used any more
4796 {
4797  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
4798  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4799  {
4800  if(TrackVector.at(x).TrackType == Erase)
4801  {
4802  Utilities->CallLogPop(498);
4803  return false;
4804  }
4805 
4806 // check foot linkages
4807  if(TrackVector.at(x).TrackType == FootCrossing)
4808  {
4809  if(!CheckFootCrossingLinks(2, TrackVector.at(x)))
4810  {
4811  Utilities->CallLogPop(499);
4812  return false;
4813  }
4814  }
4815 
4816  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4817  {
4818  if(TrackVector.at(x).Link[y] <= 0)
4819  continue; // no link
4820  if(TrackVector.at(x).Config[y] == End)
4821  continue; // buffer or continuation
4822  if(TrackVector.at(x).Config[y] == Gap)
4823  continue; // gaps set later from GapMap
4824 
4825  // get required H & V for track element joining link 'y'
4826  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4827  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4828  // find track element if present
4829  bool ConnectionFoundFlag = false;
4830  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
4831  if(ConnectionFoundFlag)
4832  {
4833  TrackVector.at(x).Conn[y] = VecPos;
4834  // find connecting link in the newly found track element if there is one & make buffer check
4835  bool LinkFoundFlag = false;
4836  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4837  (TrackVector.at(VecPos).TrackType == Buffers))
4838  {
4839  Utilities->CallLogPop(500);
4840  return false;
4841  }
4842  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4843  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4844  {
4845  Utilities->CallLogPop(501);
4846  return false;
4847  }
4848  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == Continuation))
4849  {
4850  Utilities->CallLogPop(502);
4851  return false;
4852  }
4853  else
4854  {
4855  for(unsigned int a = 0; a < 4; a++)
4856  {
4857  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4858  (TrackVector.at(VecPos).Config[a] != Gap))
4859  {
4860  TrackVector.at(x).ConnLinkPos[y] = a;
4861  // note - this ensures that if the connecting element is a leading point
4862  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4863  // (Points have the same link value for both [0] and [2])
4864  LinkFoundFlag = true;
4865  break; // stop after first find or will find later link for leading point
4866  }
4867  }
4868  }
4869  if(!LinkFoundFlag)
4870  {
4871  Utilities->CallLogPop(503);
4872  return false;
4873  }
4874  }
4875  else // if(ConnectionFoundFlag)
4876  {
4877  Utilities->CallLogPop(504);
4878  return false;
4879  }
4880  }
4881  } // for(unsigned int x=0;x<TrackVector.size();x++)
4882 
4883 // final check
4884  bool ConnErrorFlag = false;
4885 
4886  for(unsigned int x = 0; x < TrackVector.size(); x++)
4887  {
4888  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4889  ConnErrorFlag = true;
4890  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4891  ConnErrorFlag = true;
4892  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4893  ConnErrorFlag = true;
4894  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4895  ConnErrorFlag = true;
4896  }
4897  if(ConnErrorFlag)
4898  {
4899  Utilities->CallLogPop(505);
4900  return false;
4901  }
4902 
4903  bool CLkErrorFlag = false;
4904 
4905  for(unsigned int x = 0; x < TrackVector.size(); x++)
4906  {
4907  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4908  CLkErrorFlag = true;
4909  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4910  CLkErrorFlag = true;
4911  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4912  CLkErrorFlag = true;
4913  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4914  CLkErrorFlag = true;
4915  }
4916 
4917  if(CLkErrorFlag)
4918  {
4919  Utilities->CallLogPop(506);
4920  return false;
4921  }
4922  Utilities->CallLogPop(507);
4923  return true;
4924 }
4925 
4926 // ---------------------------------------------------------------------------
4927 
4929 {
4930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
4931  int Position1, Position2;
4932  TTrackElement TrackElement1, TrackElement2;
4933  TGapMapIterator GapMapPtr;
4934 
4935  if(!GapMap.empty())
4936  {
4937  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
4938  {
4939  int HLoc1 = GapMapPtr->first.first;
4940  int VLoc1 = GapMapPtr->first.second;
4941  int HLoc2 = GapMapPtr->second.first;
4942  int VLoc2 = GapMapPtr->second.second;
4943  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
4944  {
4945  throw Exception("Failed to find H & V for gap1, GapMap in error");
4946  }
4947  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
4948  {
4949  throw Exception("Failed to find H & V for gap2, GapMap in error");
4950  }
4951  if(TrackElementAt(9, Position1).TrackType != GapJump)
4952  {
4953  throw Exception("Element at Pos1 not a gap, GapMap in error");
4954  }
4955  if(TrackElementAt(10, Position2).TrackType != GapJump)
4956  {
4957  throw Exception("Element at Pos2 not a gap, GapMap in error");
4958  }
4959  TrackElementAt(11, Position1).Conn[0] = Position2;
4960  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
4961  TrackElementAt(13, Position2).Conn[0] = Position1;
4962  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
4963  }
4964  }
4965  Utilities->CallLogPop(510);
4966  return true;
4967 }
4968 
4969 // ---------------------------------------------------------------------------
4970 
4971 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
4972 {
4973 // TIMPair MapEntry;
4974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
4975  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
4976  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
4977  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
4978  TLocationNameMultiMapEntry LocationNameEntry;
4979 
4980  LocationNameEntry.first = TrackElement.LocationName;
4981  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
4982  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
4983  {
4984 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
4985 // could arise when loading old railways with multiple NonStationNamedLocs
4986  bool FoundFlag = false;
4987  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
4988  if(FoundFlag)
4989  {
4990  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
4991  IMPair.second).SpeedTag == TrackElement.SpeedTag))
4992  {
4993  Utilities->CallLogPop(1813);
4994  return;
4995  }
4996  }
4997  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
4998  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
4999  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5000  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5001  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5002  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5003  if(TrackElement.FixedNamedLocationElement)
5004  {
5005  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5006  LocationNameMultiMap.insert(LocationNameEntry);
5007  }
5008  if(TrackElement.HLoc < HLocMin)
5009  HLocMin = TrackElement.HLoc;
5010  if(TrackElement.HLoc > HLocMax)
5011  HLocMax = TrackElement.HLoc;
5012  if(TrackElement.VLoc < VLocMin)
5013  VLocMin = TrackElement.VLoc;
5014  if(TrackElement.VLoc > VLocMax)
5015  VLocMax = TrackElement.VLoc;
5016  }
5017  else
5018  {
5019 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5020 // shouldn't arise but leave in as a safeguard
5021  bool FoundFlag = false;
5022  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5023  if(FoundFlag)
5024  {
5025  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5026  {
5027  Utilities->CallLogPop(1814);
5028  return;
5029  }
5030  }
5031  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5032  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5033  {
5034  TrackMapKeyPair.first = TrackElement.HLoc;
5035  TrackMapKeyPair.second = TrackElement.VLoc;
5036  TrackMapEntry.first = TrackMapKeyPair;
5037  TrackMapEntry.second = TrackVector.size() - 1;
5038  TrackMap.insert(TrackMapEntry);
5039  if(TrackElement.FixedNamedLocationElement)
5040  {
5041  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap
5042  LocationNameMultiMap.insert(LocationNameEntry);
5043  }
5044  if(TrackElement.HLoc < HLocMin)
5045  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5046  if(TrackElement.HLoc > HLocMax)
5047  HLocMax = TrackElement.HLoc;
5048  if(TrackElement.VLoc < VLocMin)
5049  VLocMin = TrackElement.VLoc;
5050  if(TrackElement.VLoc > VLocMax)
5051  VLocMax = TrackElement.VLoc;
5052  }
5053  }
5054 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5055 // CheckMapAndInactiveTrack(6);//test
5056 
5057 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5058 // with the Platforms until layout fully loaded
5059  Utilities->CallLogPop(511);
5060 }
5061 
5062 // ---------------------------------------------------------------------------
5063 
5064 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5065 {
5066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5067  AnsiString(VLoc));
5068  THVPair TrackMapKeyPair;
5069 
5070  FoundFlag = false;
5071  TTrackMapIterator TrackMapPtr;
5072 
5073  TrackMapKeyPair.first = HLoc;
5074  TrackMapKeyPair.second = VLoc;
5075  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5076  if(TrackMapPtr == TrackMap.end())
5077  {
5078  Utilities->CallLogPop(512);
5079  return -1; // nothing found
5080  }
5081  else
5082  {
5083  FoundFlag = true;
5084  Utilities->CallLogPop(513);
5085  return TrackMapPtr->second;
5086  }
5087 }
5088 
5089 // ---------------------------------------------------------------------------
5090 
5091 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5092 {
5093  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5094  AnsiString(VLoc));
5095  THVPair TrackMapKeyPair;
5096  TTrackMapIterator TrackMapPtr;
5097 
5098  TrackMapKeyPair.first = HLoc;
5099  TrackMapKeyPair.second = VLoc;
5100  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5101  if(TrackMapPtr == TrackMap.end())
5102  {
5103  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5104  throw Exception(Message);
5105  }
5106  else
5107  {
5108  Utilities->CallLogPop(1943);
5109  return TrackElementAt(871, TrackMapPtr->second);
5110  }
5111 }
5112 
5113 // ---------------------------------------------------------------------------
5114 
5116 {
5117  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5118  AnsiString(VLoc));
5119  THVPair InactiveTrackMapKeyPair;
5120  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5121 
5122  InactiveTrackMapKeyPair.first = HLoc;
5123  InactiveTrackMapKeyPair.second = VLoc;
5124  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5125  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5126  {
5127  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5128  throw Exception(Message);
5129  }
5130  else
5131  {
5132  Utilities->CallLogPop(1949);
5133  return InactiveTrackElementAt(34, InactiveTrackMapPtr->second);
5134  }
5135 }
5136 
5137 // ---------------------------------------------------------------------------
5138 
5139 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5140 {
5141  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5142  bool Present = true;
5143  THVPair TrackMapKeyPair;
5144  TTrackMapIterator TrackMapPtr;
5145 
5146  TrackMapKeyPair.first = HLoc;
5147  TrackMapKeyPair.second = VLoc;
5148  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5149  if(TrackMapPtr == TrackMap.end())
5150  {
5151  Present = false;
5152  }
5153  Utilities->CallLogPop(2057);
5154  return Present;
5155 }
5156 
5157 // ---------------------------------------------------------------------------
5158 
5159 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5160 {
5161  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5162  AnsiString(VLoc));
5163  bool Present = true;
5164  THVPair InactiveTrackMapKeyPair;
5165  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5166 
5167  InactiveTrackMapKeyPair.first = HLoc;
5168  InactiveTrackMapKeyPair.second = VLoc;
5169  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5170  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5171  {
5172  Present = false;
5173  }
5174  Utilities->CallLogPop(2058);
5175  return Present;
5176 }
5177 
5178 // ---------------------------------------------------------------------------
5179 
5180 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5181  // max number of elements is 2, for platforms
5182  // note that both elements of RetPair may be the same, if only one present in map
5183 {
5184  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5185  AnsiString(VLoc));
5186  THVPair InactiveTrackMapKeyPair;
5187  TIMPair RetPair;
5188  TInactiveTrackRange InactiveTrackRange;
5189 
5190  FoundFlag = false;
5191  InactiveTrackMapKeyPair.first = HLoc;
5192  InactiveTrackMapKeyPair.second = VLoc;
5193  if(InactiveTrack2MultiMap.empty())
5194  {
5195  RetPair.first = 0;
5196  RetPair.second = 0;
5197  Utilities->CallLogPop(1815);
5198  return RetPair; // map empty
5199  }
5200  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5201  if(InactiveTrackRange.first == InactiveTrackRange.second)
5202  {
5203  RetPair.first = 0;
5204  RetPair.second = 0;
5205  Utilities->CallLogPop(514);
5206  return RetPair; // nothing found
5207  }
5208  else
5209  {
5210  RetPair.first = InactiveTrackRange.first->second;
5211  RetPair.second = (--InactiveTrackRange.second)->second;
5212  FoundFlag = true;
5213  Utilities->CallLogPop(515);
5214  return RetPair;
5215  }
5216 }
5217 
5218 // ---------------------------------------------------------------------------
5219 
5220 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5221 {
5222 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5223  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5224  AnsiString(DivergingPosition));
5225  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5226  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5227  int SpeedTag1 = T1.SpeedTag;
5228  int SpeedTag2 = T2.SpeedTag;
5229 
5230  if(T1.Attribute != T2.Attribute)
5231  {
5232  Utilities->CallLogPop(516);
5233  return false;
5234  }
5235  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5236  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5237  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5238  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5239  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5240  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5241  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5242  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5243  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5244  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5245  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5246  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5247  {
5248  Utilities->CallLogPop(517);
5249  return true;
5250  }
5251  else
5252  {
5253  Utilities->CallLogPop(518);
5254  return false;
5255  }
5256 }
5257 
5258 // ---------------------------------------------------------------------------
5259 
5260 /*
5261  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5262  {
5263  if(lower.second < higher.second) return true;
5264  else if(lower.second > higher.second) return false;
5265  else if(lower.second == higher.second)
5266  {
5267  if(lower.first < higher.first) return true;
5268  }
5269  return false;
5270  }
5271 */
5272 // ---------------------------------------------------------------------------
5273 
5274 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5275  // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5276 {
5277  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5278  if(TrackElement.TrackType != GapJump)
5279  {
5280  throw Exception("Error, Wrong track type in PlotGap");
5281  }
5282  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5283  {
5284  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5285  }
5286  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5287  {
5288  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5289  }
5290  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5291  {
5292  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5293  }
5294  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5295  {
5296  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5297  }
5298  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5299  {
5300  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5301  }
5302  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5303  {
5304  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5305  }
5306  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5307  {
5308  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5309  }
5310  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5311  {
5312  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5313  }
5314  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5315  {
5316  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5317  }
5318  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5319  {
5320  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5321  }
5322  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5323  {
5324  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5325  }
5326  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5327  {
5328  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5329  }
5330  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5331  {
5332  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5333  }
5334  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5335  {
5336  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5337  }
5338  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5339  {
5340  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5341  }
5342  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5343  {
5344  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5345  }
5346  Utilities->CallLogPop(1101);
5347 }
5348 
5349 // ---------------------------------------------------------------------------
5350 
5351 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5352 {
5353  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5354  if(TrackElement.TrackType != Points)
5355  {
5356  throw Exception("Error, Wrong track type in PlotPoints");
5357  }
5358  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5359  TrackElement.PlotVariableTrackElement(4, Disp);
5360  if(BothFillets)
5361  {
5362  if(TrackElement.SpeedTag < 28)
5363  {
5364  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5365  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5366  }
5367  else if(TrackElement.SpeedTag < 132)
5368  {
5369  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5370  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5371  }
5372  else
5373  {
5374  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5375  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5376  }
5377  }
5378  else
5379  {
5380  if(TrackElement.SpeedTag < 28)
5381  {
5382  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5383  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5384  }
5385  else if(TrackElement.SpeedTag < 132)
5386  {
5387  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5388  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5389  }
5390  else
5391  {
5392  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5393  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5394  }
5395  }
5396 // replot platform if required
5397  TIMPair IMPair;
5398  bool FoundFlag;
5399 
5400  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5401  if(FoundFlag)
5402  { // only one platform possible at points so only need to plot IMPair.first
5403  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5404  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5405  }
5406  Utilities->CallLogPop(519);
5407 }
5408 
5409 // ---------------------------------------------------------------------------
5410 
5411 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5412 {
5413 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5414  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5415  if(TrackElement.TrackType != SignalPost)
5416  {
5417  throw Exception("Error, Wrong track type in PlotSignal");
5418  }
5419  for(int x = 0; x < 40; x++)
5420  {
5421  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5422  {
5423  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5424  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5425 // in case existing signal is a double yellow
5426  // plot platforms if present
5427 // Graphics::TBitmap* SignalPlatformGraphic;
5428 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5429 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5430 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5431 // to not be plotted with the above function.
5432  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5433  // now plot signal (double yellow overwrites most of signal platform if present)
5434  // additions at version 0.6 for other aspects & ground sigs
5435  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5436  {
5437  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5438  }
5439  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5440  {
5441  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5442  }
5443  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5444  {
5445  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5446  }
5447  else // 4 aspect
5448  {
5449  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5450  }
5451  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5452  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5453  {
5454  if(TrackElement.SpeedTag == 68)
5455  {
5456  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5457  }
5458  if(TrackElement.SpeedTag == 69)
5459  {
5460  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5461  }
5462  if(TrackElement.SpeedTag == 70)
5463  {
5464  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5465  }
5466  if(TrackElement.SpeedTag == 71)
5467  {
5468  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5469  }
5470  if(TrackElement.SpeedTag == 72)
5471  {
5472  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5473  }
5474  if(TrackElement.SpeedTag == 73)
5475  {
5476  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5477  }
5478  if(TrackElement.SpeedTag == 74)
5479  {
5480  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5481  }
5482  if(TrackElement.SpeedTag == 75)
5483  {
5484  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5485  }
5486  }
5487  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5488  // ground signal calling on, need to use normal proceed aspect
5489  {
5490  for(int x = 0; x < 40; x++)
5491  {
5492  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5493  {
5494  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5495  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5496  // plot special signal platform if present
5497  Graphics::TBitmap* SignalPlatformGraphic;
5498  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5499  // now plot signal
5500  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5501  }
5502  }
5503  }
5504  break;
5505  }
5506  }
5507  Utilities->CallLogPop(520);
5508 }
5509 
5510 // ---------------------------------------------------------------------------
5511 
5512 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
5513 {
5514  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5515  bool FoundFlag;
5516  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
5517 
5518  if(!FoundFlag)
5519  {
5520  Utilities->CallLogPop(2112);
5521  return;
5522  }
5523  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
5524  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
5525 
5526  // don't want 'else if' for the below as may need to plot 2 platforms
5527  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
5528  {
5529  if(IAElement1.LocationName == "") // '2' will be same
5530  {
5531  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
5532  }
5533  else
5534  {
5535  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
5536  }
5537  }
5538  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
5539  {
5540  if(IAElement1.LocationName == "") // '2' will be same
5541  {
5542  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
5543  }
5544  else
5545  {
5546  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
5547  }
5548  }
5549  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
5550  {
5551  if(IAElement1.LocationName == "") // '2' will be same
5552  {
5553  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
5554  }
5555  else
5556  {
5557  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
5558  }
5559  }
5560  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
5561  {
5562  if(IAElement1.LocationName == "") // '2' will be same
5563  {
5564  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
5565  }
5566  else
5567  {
5568  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
5569  }
5570  }
5571  Utilities->CallLogPop(2113);
5572 }
5573 
5574 // ---------------------------------------------------------------------------
5575 
5576 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
5577 {
5578 // Set attrs to 0=closed to trains; 1=open to trains; 3 = changing = closed to trains
5579  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
5580  AnsiString(VLoc));
5581 // find topmost LC, opening them all (to trains) in turn
5582  int UpStep = 0;
5583 
5584  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5585  {
5586  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
5587  UpStep--;
5588  }
5589 // now find bottommost LC, opening them all (to trains) in turn
5590  int DownStep = 1;
5591 
5592  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
5593  {
5594  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
5595  DownStep++;
5596  }
5597 // find leftmost LC, opening them all (to trains) in turn
5598  int LeftStep = 0;
5599 
5600  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
5601  {
5602  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
5603  LeftStep--;
5604  }
5605 // now find rightmost LC, opening them all (to trains) in turn
5606  int RightStep = 1;
5607 
5608  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
5609  {
5610  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
5611  RightStep++;
5612  }
5613  Utilities->CallLogPop(1915);
5614 }
5615 
5616 // ---------------------------------------------------------------------------
5617 
5618 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
5619  // open to trains
5620  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5621 {
5622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
5623  AnsiString(VLoc));
5624  if(!IsLCAtHV(4, HLoc, VLoc))
5625  {
5626  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
5627  }
5628  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5629  {
5630  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
5631  }
5632 // check for adjacent LCs & if so open (to trains)
5633  if(BaseElementSpeedTag == 1) // hor track element
5634  {
5635  // find topmost LC, opening them all (to trains) in turn
5636  int UpStep = 0;
5637  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5638  {
5639  UpStep--;
5640  }
5641  UpStep++;
5642  // now find bottommost LC, opening them all (to trains) in turn
5643  int DownStep = 1;
5644  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
5645  {
5646  DownStep++;
5647  }
5648  DownStep--;
5649  // now plot graphics, UpStep is smallest & DownStep largest
5650  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
5651  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
5652  Graphics::TBitmap *RouteGraphic;
5653  if(ConsecSignals)
5654  {
5655  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
5656  }
5657  else
5658  {
5659  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
5660  }
5661  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
5662 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5663 // LinkSigRouteGraphicsPtr[1] ver }
5664 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5665 // LinkNonSigRouteGraphicsPtr[1] ver }
5666 
5667  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5668  {
5669  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5670  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
5671  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
5672  }
5673  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
5674  {
5675  if(UpStep == 0)
5676  {
5677  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5678  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5679  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5680  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5681  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5682  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5683  }
5684  else
5685  {
5686  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5687  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5688  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5689  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5690  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5691  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5692  }
5693  }
5694  else // at least one plain graphic
5695  {
5696  if(UpStep == 0)
5697  {
5698  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5699  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5700  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5701  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5702  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5703  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5704  }
5705  else if(DownStep == 0)
5706  {
5707  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5708  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5709  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5710  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5711  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5712  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5713  }
5714  else
5715  {
5716  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5717  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5718  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5719  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5720  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5721  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5722  }
5723  for(int x = (UpStep + 1); x < DownStep; x++)
5724  {
5725  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
5726  if(x == 0)
5727  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
5728  else
5729  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
5730  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
5731  }
5732  }
5733  Disp->Update();
5734  Utilities->CallLogPop(1958);
5735  return;
5736  }
5737 
5738  else // ver track element
5739  {
5740  // find leftmost LC, opening them all (to trains) in turn
5741  int LStep = 0;
5742  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
5743  {
5744  LStep--;
5745  }
5746  LStep++;
5747  // now find rightmost LC, opening them all (to trains) in turn
5748  int RStep = 1;
5749  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
5750  {
5751  RStep++;
5752  }
5753  RStep--;
5754  // now plot graphics, LStep is smallest & RStep largest
5755  Graphics::TBitmap *RouteGraphic;
5756  if(ConsecSignals)
5757  {
5758  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
5759  }
5760  else
5761  {
5762  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
5763  }
5764  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
5765 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5766 // LinkSigRouteGraphicsPtr[1] ver }
5767 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5768 // LinkNonSigRouteGraphicsPtr[1] ver }
5769  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5770  {
5771  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5772  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
5773  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
5774  }
5775  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
5776  {
5777  if(LStep == 0)
5778  {
5779  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5780  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
5781  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5782  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5783  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
5784  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5785  }
5786  else
5787  {
5788  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5789  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
5790  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5791  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5792  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
5793  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5794  }
5795  }
5796  else // at least one plain graphic
5797  {
5798  if(LStep == 0)
5799  {
5800  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5801  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
5802  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5803  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5804  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
5805  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5806  }
5807  else if(RStep == 0)
5808  {
5809  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5810  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
5811  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5812  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5813  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
5814  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5815  }
5816  else
5817  {
5818  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5819  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
5820  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5821  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5822  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
5823  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5824  }
5825  for(int x = (LStep + 1); x < RStep; x++)
5826  {
5827  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5828  if(x == 0)
5829  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
5830  else
5831  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
5832  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
5833  }
5834  }
5835  Disp->Update();
5836  Utilities->CallLogPop(1896);
5837  return;
5838  }
5839 }
5840 
5841 // ---------------------------------------------------------------------------
5842 
5843 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // open to trains
5844  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5845 {
5846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
5847  AnsiString(HLoc) + "," + AnsiString(VLoc));
5848  if(!IsLCAtHV(29, HLoc, VLoc))
5849  {
5850  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
5851  }
5852  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5853  {
5854  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
5855  }
5856 // check for adjacent LCs & if so open (to trains)
5857  if(BaseElementSpeedTag == 1) // hor track element
5858  {
5859  // find topmost LC, opening them all (to trains) in turn
5860  int UpStep = 0;
5861  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5862  {
5863  UpStep--;
5864  }
5865  UpStep++;
5866  // now find bottommost LC, opening them all (to trains) in turn
5867  int DownStep = 1;
5868  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
5869  {
5870  DownStep++;
5871  }
5872  DownStep--;
5873  // now plot graphics, UpStep is smallest & DownStep largest
5874  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5875  {
5876  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
5877  }
5878  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
5879  {
5880  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5881  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5882  }
5883  else // at least one plain graphic
5884  {
5885  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5886  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5887  for(int x = (UpStep + 1); x < DownStep; x++)
5888  {
5889  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
5890  }
5891  }
5892  // set markers
5893  for(int x = UpStep; x <= DownStep; x++)
5894  {
5895  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).TempMarker = true; // plotted
5896  }
5897  Display->Update();
5898  Utilities->CallLogPop(1944);
5899  return;
5900  }
5901 
5902  else // ver track element
5903  {
5904  // find leftmost LC, opening them all (to trains) in turn
5905  int LStep = 0;
5906  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
5907  {
5908  LStep--;
5909  }
5910  LStep++;
5911  // now find rightmost LC, opening them all (to trains) in turn
5912  int RStep = 1;
5913  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
5914  {
5915  RStep++;
5916  }
5917  RStep--;
5918  // now plot graphics, LStep is smallest & RStep largest
5919  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5920  {
5921  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
5922  }
5923  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
5924  {
5925  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5926  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5927  }
5928  else // at least one plain graphic
5929  {
5930  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5931  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5932  for(int x = (LStep + 1); x < RStep; x++)
5933  {
5934  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
5935  }
5936  }
5937  // set markers
5938  for(int x = LStep; x <= RStep; x++)
5939  {
5940  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).TempMarker = true; // plotted
5941  }
5942  Disp->Update();
5943  Utilities->CallLogPop(1945);
5944  return;
5945  }
5946 }
5947 
5948 // ---------------------------------------------------------------------------
5949 
5950 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
5951  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5952 {
5953  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
5954  AnsiString(VLoc));
5955  if(!IsLCAtHV(9, HLoc, VLoc))
5956  {
5957  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
5958  }
5959  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5960  {
5961  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
5962  }
5963 // check for adjacent LCs & if so close (to trains)
5964  if(BaseElementSpeedTag == 1) // hor track element
5965  {
5966  // find topmost LC, closing them all (to trains) in turn
5967  int UpStep = 0;
5968  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5969  {
5970  UpStep--;
5971  }
5972  UpStep++;
5973  // now find bottommost LC, opening them all (to trains) in turn
5974  int DownStep = 1;
5975  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
5976  {
5977  DownStep++;
5978  }
5979  DownStep--;
5980  // now plot graphics, UpStep is smallest & DownStep largest
5981  for(int x = UpStep; x < (DownStep + 1); x++)
5982  {
5983  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
5984  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
5985  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
5986  }
5987  Disp->Update();
5988  Utilities->CallLogPop(1959);
5989  return;
5990  }
5991 
5992  else // ver track element
5993  {
5994  // find leftmost LC, closing them all (to trains) in turn
5995  int LStep = 0;
5996  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
5997  {
5998  LStep--;
5999  }
6000  LStep++;
6001  // now find rightmost LC, opening them all (to trains) in turn
6002  int RStep = 1;
6003  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6004  {
6005  RStep++;
6006  }
6007  RStep--;
6008  // now plot graphics, LStep is smallest & RStep largest
6009  for(int x = LStep; x < (RStep + 1); x++)
6010  {
6011  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6012  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6013  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6014  }
6015  Disp->Update();
6016  Utilities->CallLogPop(1960);
6017  return;
6018  }
6019 }
6020 
6021 // ---------------------------------------------------------------------------
6022 
6023 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6024  // closed to trains
6025  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6026 {
6027  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6028  AnsiString(HLoc) + "," + AnsiString(VLoc));
6029  if(!IsLCAtHV(34, HLoc, VLoc))
6030  {
6031  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6032  }
6033  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6034  {
6035  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6036  }
6037  TTrackElement TE;
6038 
6039 // check for adjacent LCs & if so close (to trains)
6040  if(BaseElementSpeedTag == 1) // hor track element
6041  {
6042  // find topmost LC, closing them all (to trains) in turn
6043  int UpStep = 0;
6044  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6045  {
6046  UpStep--;
6047  }
6048  UpStep++;
6049  // now find bottommost LC, opening them all (to trains) in turn
6050  int DownStep = 1;
6051  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6052  {
6053  DownStep++;
6054  }
6055  DownStep--;
6056  // now plot graphics, UpStep is smallest & DownStep largest
6057  for(int x = UpStep; x <= DownStep; x++)
6058  {
6059  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6060  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).TempMarker = true; // plotted
6061  }
6062  Display->Update();
6063  Utilities->CallLogPop(1946);
6064  return;
6065  }
6066 
6067  else // ver track element
6068  {
6069  // find leftmost LC, closing them all (to trains) in turn
6070  int LStep = 0;
6071  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6072  {
6073  LStep--;
6074  }
6075  LStep++;
6076  // now find rightmost LC, opening them all (to trains) in turn
6077  int RStep = 1;
6078  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6079  {
6080  RStep++;
6081  }
6082  RStep--;
6083  // now plot graphics, LStep is smallest & RStep largest
6084  for(int x = LStep; x <= RStep; x++)
6085  {
6086  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6087  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).TempMarker = true; // plotted
6088  }
6089  Display->Update();
6090  Utilities->CallLogPop(1947);
6091  return;
6092  }
6093 }
6094 
6095 // ---------------------------------------------------------------------------
6096 
6097 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
6098 {
6099  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6100  Graphics::TBitmap *RouteGraphic;
6101  Graphics::TBitmap *BaseGraphic;
6102 
6103  if(BaseElementSpeedTag == 1)
6104  {
6105  if(ConsecSignals)
6106  {
6107  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6108  }
6109  else
6110  {
6111  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6112  }
6113  BaseGraphic = RailGraphics->gl1;
6114  if(State == Raising)
6115  RouteGraphic = BaseGraphic;
6116  }
6117  else
6118  {
6119  if(ConsecSignals)
6120  {
6121  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6122  }
6123  else
6124  {
6125  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6126  }
6127  BaseGraphic = RailGraphics->gl2;
6128  if(State == Raising)
6129  RouteGraphic = BaseGraphic;
6130  }
6131  int UpStep = 0;
6132 
6133  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6134  {
6135  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6136  if(UpStep == 0)
6137  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6138  else
6139  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6140  UpStep--;
6141  }
6142 // now find bottommost LC, opening them all (to trains) in turn
6143  int DownStep = 1;
6144 
6145  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
6146  {
6147  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6148  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6149  DownStep++;
6150  }
6151  int LeftStep = 0;
6152 
6153  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6154  {
6155  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6156  if(LeftStep == 0)
6157  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
6158  else
6159  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
6160  LeftStep--;
6161  }
6162 // now find rightmost LC, opening them all (to trains) in turn
6163  int RightStep = 1;
6164 
6165  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
6166  {
6167  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6168  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
6169  RightStep++;
6170  }
6171  Disp->Update();
6172  Utilities->CallLogPop(1914);
6173 }
6174 
6175 // ---------------------------------------------------------------------------
6176 
6177 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
6178 {
6179 // return false for no LC there, flashing or a closed (to trains) LC
6180  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6181  bool FoundFlag;
6182  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
6183 
6184  if(!FoundFlag)
6185  {
6186  Utilities->CallLogPop(1898);
6187  return false;
6188  }
6189  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6190  {
6191  Utilities->CallLogPop(1899);
6192  return false;
6193  }
6194  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
6195  {
6196  Utilities->CallLogPop(1900);
6197  return true;
6198  }
6199  Utilities->CallLogPop(1901);
6200  return false;
6201 }
6202 
6203 // ---------------------------------------------------------------------------
6204 
6205 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
6206 {
6207 // return false for no LC there, flashing LC or open (to trains) LC
6208  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6209  bool FoundFlag;
6210  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
6211 
6212  if(!FoundFlag)
6213  {
6214  Utilities->CallLogPop(1922);
6215  return false;
6216  }
6217  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6218  {
6219  Utilities->CallLogPop(1923);
6220  return false;
6221  }
6222  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
6223  {
6224  Utilities->CallLogPop(1924);
6225  return true;
6226  }
6227  Utilities->CallLogPop(1925);
6228  return false;
6229 }
6230 
6231 // ---------------------------------------------------------------------------
6232 
6233 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
6234 {
6235 // return true for barrier in process of moving
6236  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6237  bool FoundFlag;
6238  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
6239 
6240  if(!FoundFlag)
6241  {
6242  Utilities->CallLogPop(1918);
6243  return false;
6244  }
6245  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6246  {
6247  Utilities->CallLogPop(1919);
6248  return false;
6249  }
6250  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
6251  {
6252  Utilities->CallLogPop(1920);
6253  return true;
6254  }
6255  Utilities->CallLogPop(1921);
6256  return false;
6257 }
6258 
6259 // ---------------------------------------------------------------------------
6260 
6261 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
6262 {
6263 // return true for an LC at H&V
6264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6265  bool FoundFlag;
6266  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
6267 
6268  if(!FoundFlag)
6269  {
6270  Utilities->CallLogPop(1902);
6271  return false;
6272  }
6273  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6274  {
6275  Utilities->CallLogPop(1903);
6276  return false;
6277  }
6278  Utilities->CallLogPop(1904);
6279  return true;
6280 }
6281 
6282 // ---------------------------------------------------------------------------
6283 
6284 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
6285 {
6286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6287  AnsiString(Attr));
6288  bool FoundFlag;
6289  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
6290 
6291  if(!FoundFlag)
6292  {
6293  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6294  }
6295  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6296  {
6297  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6298  }
6299  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
6300  Utilities->CallLogPop(1905);
6301  return;
6302 }
6303 
6304 // ---------------------------------------------------------------------------
6305 
6307 {
6308  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
6309  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
6310  {
6311  TTrackElement InactiveTrackElement = InactiveTrackVector.at(x);
6312  if(InactiveTrackElement.TrackType == LevelCrossing)
6313  {
6314  InactiveTrackVector.at(x).Attribute = 0;
6315  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
6316  }
6317  }
6318  Utilities->CallLogPop(1913);
6319  return;
6320 }
6321 
6322 // ---------------------------------------------------------------------------
6323 
6324 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
6325 {
6326 // return true if there is either a route set on any element or a train on any element
6327  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
6328  "," + AnsiString(VLoc));
6329 
6330  THVPair TrackMapKeyPair;
6331  TTrack::TTrackMapIterator TrackMapPtr;
6332  int DummyRouteNumber;
6333 
6334  TrainPresent = false;
6335 // find topmost LC, checking each for routes & trains
6336  int UpStep = 0;
6337 
6338  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6339  {
6340  TrackMapKeyPair.first = HLoc;
6341  TrackMapKeyPair.second = VLoc + UpStep;
6342  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6343  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6344  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6345  {
6346  Utilities->CallLogPop(1932);
6347  return true;
6348  }
6349  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
6350  {
6351  TrainPresent = true;
6352  Utilities->CallLogPop(1933);
6353  return true;
6354  }
6355  UpStep--;
6356  }
6357 // now find bottommost LC, opening them all (to trains) in turn
6358  int DownStep = 1;
6359 
6360  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
6361  {
6362  TrackMapKeyPair.first = HLoc;
6363  TrackMapKeyPair.second = VLoc + DownStep;
6364  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6365  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6366  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6367  {
6368  Utilities->CallLogPop(1934);
6369  return true;
6370  }
6371  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
6372  {
6373  TrainPresent = true;
6374  Utilities->CallLogPop(1935);
6375  return true;
6376  }
6377  DownStep++;
6378  }
6379 // find leftmost LC
6380  int LeftStep = 0;
6381 
6382  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6383  {
6384  TrackMapKeyPair.first = HLoc + LeftStep;
6385  TrackMapKeyPair.second = VLoc;
6386  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6387  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6388  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6389  {
6390  Utilities->CallLogPop(1936);
6391  return true;
6392  }
6393  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
6394  {
6395  TrainPresent = true;
6396  Utilities->CallLogPop(1937);
6397  return true;
6398  }
6399  LeftStep--;
6400  }
6401 // now find rightmost LC, opening them all (to trains) in turn
6402  int RightStep = 1;
6403 
6404  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
6405  {
6406  TrackMapKeyPair.first = HLoc + RightStep;
6407  TrackMapKeyPair.second = VLoc;
6408  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6409  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6410  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6411  {
6412  Utilities->CallLogPop(1938);
6413  return true;
6414  }
6415  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
6416  {
6417  TrainPresent = true;
6418  Utilities->CallLogPop(1939);
6419  return true;
6420  }
6421  RightStep++;
6422  }
6423  Utilities->CallLogPop(1940);
6424  return false;
6425 }
6426 
6427 // ---------------------------------------------------------------------------
6428 
6429 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
6430 {
6431  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
6432  if(TrackElement.TrackType != Points)
6433  {
6434  throw Exception("Error, Wrong track type in GetFilletGraphic");
6435  }
6436  if(TrackElement.SpeedTag < 28)
6437  {
6438  Utilities->CallLogPop(521);
6439  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute];
6440  }
6441  else if(TrackElement.SpeedTag < 132)
6442  {
6443  Utilities->CallLogPop(522);
6444 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6445  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute];
6446  }
6447  else
6448  {
6449  Utilities->CallLogPop(1537);
6450  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute];
6451  }
6452 }
6453 
6454 // ---------------------------------------------------------------------------
6455 
6457 {
6458  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
6459  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
6460  {
6461  TrackVector.at(x).TrainIDOnElement = -1;
6462  TrackVector.at(x).TrainIDOnBridgeTrackPos01 = -1;
6463  TrackVector.at(x).TrainIDOnBridgeTrackPos23 = -1;
6464  }
6465  Utilities->CallLogPop(1342);
6466 }
6467 
6468 // ---------------------------------------------------------------------------
6469 
6470 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
6471 /*
6472  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
6473 */
6474 {
6475  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6476  AnsiString(ScreenPosV));
6477  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
6478  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
6479 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6480  Utilities->CallLogPop(535);
6481 }
6482 
6483 // ---------------------------------------------------------------------------
6484 
6485 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
6486 /*
6487  Converts the screen position to the true (without offsets) position
6488 */
6489 {
6490  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6491  AnsiString(ScreenPosV));
6492  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
6493  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
6494  Utilities->CallLogPop(536);
6495 }
6496 
6497 // ---------------------------------------------------------------------------
6498 
6499 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
6500 {
6501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
6502  AnsiString(VPosTrue));
6503  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
6504  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
6505  Utilities->CallLogPop(537);
6506 }
6507 
6508 // ---------------------------------------------------------------------------
6509 
6510 void TTrack::CheckMapAndTrack(int Caller) // test
6511 {
6512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
6513  int Zeroes = 0;
6514  bool FoundFlag;
6515 
6516  for(unsigned int a = 0; a < TrackVector.size(); a++)
6517  {
6518  TTrackElement CheckElement = Track->TrackVector.at(a);
6519  if(CheckElement.SpeedTag == 0)
6520  {
6521  Zeroes++; // zeroed elements not saved in map
6522  }
6523  else
6524  {
6525  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6526  if(!FoundFlag)
6527  {
6528  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6529  " in TrackMap, Caller=" + (AnsiString)Caller);
6530  }
6531  if(MapVecPos != (int)a)
6532  {
6533  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6534  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
6535  (AnsiString)Caller);
6536  }
6537  }
6538  }
6539  if(TrackVector.size() != (TrackMap.size() + Zeroes))
6540  {
6541  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6542  " Caller=" + (AnsiString)Caller);
6543  }
6544  Utilities->CallLogPop(538);
6545  return;
6546 }
6547 
6548 // ---------------------------------------------------------------------------
6549 
6550 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
6551 {
6552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
6553  bool FoundFlag;
6554  TIMPair InactivePair;
6555 
6556  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
6557  {
6558  TTrackElement CheckElement = Track->InactiveTrackVector.at(a);
6559  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6560  if(!FoundFlag)
6561  {
6562  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6563  " in InactiveMap, Caller=" + (AnsiString)Caller);
6564  }
6565  if((InactivePair.first != a) && (InactivePair.second != a))
6566  {
6567  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6568  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
6569  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
6570  }
6571  }
6572  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
6573  {
6574  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6575  " Caller=" + (AnsiString)Caller);
6576  }
6577  Utilities->CallLogPop(539);
6578 }
6579 
6580 // ---------------------------------------------------------------------------
6581 
6582 void TTrack::CheckGapMap(int Caller) // test
6583 {
6584  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
6585  int Position1, Position2;
6586  TTrackElement TrackElement1, TrackElement2;
6587  TGapMapIterator GapMapPtr;
6588 
6589  if(!GapMap.empty())
6590  {
6591  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
6592  {
6593  int HLoc1 = GapMapPtr->first.first;
6594  int VLoc1 = GapMapPtr->first.second;
6595  int HLoc2 = GapMapPtr->second.first;
6596  int VLoc2 = GapMapPtr->second.second;
6597  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
6598  {
6599  throw Exception("Failed to find H & V for gap1, GapMap in error");
6600  }
6601  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
6602  {
6603  throw Exception("Failed to find H & V for gap2, GapMap in error");
6604  }
6605  if(TrackElementAt(17, Position1).TrackType != GapJump)
6606  {
6607  throw Exception("Element at Pos1 not a gap, GapMap in error");
6608  }
6609  if(TrackElementAt(18, Position2).TrackType != GapJump)
6610  {
6611  throw Exception("Element at Pos2 not a gap, GapMap in error");
6612  }
6613  }
6614  }
6615  unsigned int GapCount = 0;
6616 
6617  for(unsigned int a = 0; a < TrackVector.size(); a++)
6618  {
6619  TTrackElement CheckElement = Track->TrackVector.at(a);
6620  if(CheckElement.TrackType == GapJump)
6621  GapCount++;
6622  }
6623  if((GapMap.size() * 2) != GapCount)
6624  {
6625  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
6626  (AnsiString)Caller);
6627  }
6628  Utilities->CallLogPop(540);
6629 }
6630 
6631 // ---------------------------------------------------------------------------
6632 
6633 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
6634 {
6635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
6636  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
6637  {
6638  if(TrackFinished)
6639  {
6640  throw Exception("Error - TrackFinished with erase element still present");
6641  }
6642  Utilities->CallLogPop(541);
6643  return; // erased element, can't set ID
6644  }
6645  AnsiString IDString;
6646 
6647  if(TrackElement.HLoc < 0)
6648  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
6649  else
6650  IDString = AnsiString(TrackElement.HLoc) + "-";
6651  if(TrackElement.VLoc < 0)
6652  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
6653  else
6654  IDString += AnsiString(TrackElement.VLoc);
6655  TrackElement.ElementID = IDString;
6656  Utilities->CallLogPop(542);
6657 }
6658 
6659 // ---------------------------------------------------------------------------
6660 
6661 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
6662 {
6663 // e.g. "8-13", "00008-13", "N43-N127", etc
6664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
6665  int DelimPos;
6666 
6667  for(int x = 1; x < String.Length() + 1; x++)
6668  {
6669  if(String.IsDelimiter("-", x))
6670  {
6671  DelimPos = x;
6672  break;
6673  }
6674  if(x == String.Length())
6675  {
6676  if(GiveMessages)
6677  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
6678  Utilities->CallLogPop(543);
6679  return -1;
6680  }
6681  }
6682  if(DelimPos == 1)
6683  {
6684  if(GiveMessages)
6685  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
6686  Utilities->CallLogPop(544);
6687  return -1;
6688  }
6689  if(DelimPos == String.Length())
6690  {
6691  if(GiveMessages)
6692  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
6693  Utilities->CallLogPop(545);
6694  return -1;
6695  }
6696  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
6697  {
6698  if(GiveMessages)
6699  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
6700  Utilities->CallLogPop(1508);
6701  return -1;
6702  }
6703  int HLoc, VLoc;
6704 
6705  if(String.SubString(1, 1) != "N")
6706  {
6707  for(int x = 1; x < DelimPos; x++)
6708  {
6709  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6710  {
6711  if(GiveMessages)
6712  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
6713  Utilities->CallLogPop(546);
6714  return -1;
6715  }
6716  }
6717  }
6718  if(String.SubString(1, 1) == "N")
6719  {
6720  for(int x = 2; x < DelimPos; x++)
6721  {
6722  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6723  {
6724  if(GiveMessages)
6725  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
6726  Utilities->CallLogPop(763);
6727  return -1;
6728  }
6729  }
6730  }
6731  if(String.SubString(1, 1) == "N")
6732  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
6733  else
6734  HLoc = String.SubString(1, DelimPos - 1).ToInt();
6735 
6736  if(String.SubString(DelimPos + 1, 1) != "N")
6737  {
6738  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
6739  {
6740  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6741  {
6742  if(GiveMessages)
6743  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
6744  Utilities->CallLogPop(547);
6745  return -1;
6746  }
6747  }
6748  }
6749  if(String.SubString(DelimPos + 1, 1) == "N")
6750  {
6751  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
6752  {
6753  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6754  {
6755  if(GiveMessages)
6756  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
6757  Utilities->CallLogPop(764);
6758  return -1;
6759  }
6760  }
6761  }
6762  if(String.SubString(DelimPos + 1, 1) == "N")
6763  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
6764  else
6765  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
6766 
6767  THVPair HVPair(HLoc, VLoc);
6768  TTrackMapIterator TrackMapPtr;
6769 
6770  TrackMapPtr = TrackMap.find(HVPair);
6771  if(TrackMapPtr == TrackMap.end())
6772  {
6773  if(GiveMessages)
6774  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
6775  Utilities->CallLogPop(548);
6776  return -1;
6777  }
6778  Utilities->CallLogPop(549);
6779  return TrackMapPtr->second;
6780 }
6781 
6782 // ---------------------------------------------------------------------------
6783 
6784 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
6785 /*
6786  True for linked properly at both ends
6787 */
6788 {
6789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
6790  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
6791  int HLoc = TrackElement.HLoc;
6792  int VLoc = TrackElement.VLoc;
6793 
6794  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
6795  {
6796  Utilities->CallLogPop(1821);
6797  return false;
6798  }
6799  if(TrackElement.SpeedTag == 129) // vertical footbridge
6800  {
6801  // check top connection
6802  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
6803  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
6804  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
6805  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
6806  {
6807  Utilities->CallLogPop(550);
6808  return false;
6809  }
6810  // check bottom connection
6811  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
6812  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
6813  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
6814  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
6815  {
6816  Utilities->CallLogPop(551);
6817  return false;
6818  }
6819  }
6820  if(TrackElement.SpeedTag == 145) // vertical underpass
6821  {
6822  // check top connection
6823  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
6824  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
6825  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
6826  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
6827  {
6828  Utilities->CallLogPop(2114);
6829  return false;
6830  }
6831  // check bottom connection
6832  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
6833  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
6834  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
6835  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
6836  {
6837  Utilities->CallLogPop(2115);
6838  return false;
6839  }
6840  }
6841  if(TrackElement.SpeedTag == 130) // hor footbridge
6842  {
6843  // check left connection
6844  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
6845  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
6846  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
6847  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
6848  {
6849  Utilities->CallLogPop(552);
6850  return false;
6851  }
6852  // check right connection
6853  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
6854  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
6855  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
6856  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
6857  {
6858  Utilities->CallLogPop(553);
6859  return false;
6860  }
6861  }
6862  if(TrackElement.SpeedTag == 146) // hor u'pass
6863  {
6864  // check left connection
6865  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
6866  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
6867  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
6868  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
6869  {
6870  Utilities->CallLogPop(2116);
6871  return false;
6872  }
6873  // check right connection
6874  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
6875  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
6876  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
6877  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
6878  {
6879  Utilities->CallLogPop(2117);
6880  return false;
6881  }
6882  }
6883  Utilities->CallLogPop(554);
6884  return true;
6885 }
6886 
6887 // ---------------------------------------------------------------------------
6888 
6889 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
6890 /*
6891  return true if the SpeedTag present in the map at H & V
6892 */
6893 {
6894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6895  AnsiString(SpeedTag));
6896  if(InactiveTrack2MultiMap.empty())
6897  {
6898  Utilities->CallLogPop(555);
6899  return false;
6900  }
6901  THVPair HVPair(HLoc, VLoc);
6903  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
6904  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
6905 
6906  if(HVRange.first == HVRange.second)
6907  {
6908  Utilities->CallLogPop(556);
6909  return false;
6910  }
6911  else
6912  HVIt1 = HVRange.first;
6913  TTrackElement Temp1, Temp2; // test
6914 
6915  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
6916  if(--HVRange.second != HVRange.first)
6917  {
6918  HVIt2 = HVRange.second;
6919  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
6920  }
6921  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
6922  HVIt2->second).SpeedTag == SpeedTag)))
6923  {
6924  Utilities->CallLogPop(557);
6925  return true;
6926  }
6927  else
6928  {
6929  Utilities->CallLogPop(558);
6930  return false;
6931  }
6932 }
6933 
6934 // ---------------------------------------------------------------------------
6935 
6936 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
6937 /*
6938  return true if the SpeedTag present in the map at H & V
6939 */
6940 {
6941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6942  AnsiString(SpeedTag));
6943  if(TrackMap.empty())
6944  {
6945  Utilities->CallLogPop(559);
6946  return false;
6947  }
6948  THVPair HVPair(HLoc, VLoc);
6949  TTrackMapIterator End = TrackMap.end();
6950  TTrackMapIterator It = End;
6951 
6952  It = TrackMap.find(HVPair);
6953  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
6954  {
6955  Utilities->CallLogPop(560);
6956  return true;
6957  }
6958  else
6959  {
6960  Utilities->CallLogPop(561);
6961  return false;
6962  }
6963 }
6964 
6965 // ---------------------------------------------------------------------------
6966 
6967 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
6968 {
6969 /*
6970  General:
6971  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
6972  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
6973  a NamedNonStationLocation.
6974  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
6975  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
6976  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
6977  platform at that location).
6978 
6979  Linked named location elements are those explained in TTrack::TTrack()
6980 
6981  Detail:
6982  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
6983  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
6984  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
6985  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
6986  work OK! e.g. vector position 0 would be stored as -1, position n would be stored as -1-n. To recover the true position
6987  from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
6988 
6989  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
6990  this function a single element should be in the List (normally from the user's selection but can also be from
6991  SearchForAndUpdateLocationName), and the Map is cleared within the function.
6992  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
6993  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
6994  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
6995  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
6996  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
6997  moves them into the Map. At the end all linked elements are in the Map.
6998 
6999  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
7000  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
7001  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
7002 */
7003 
7004 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
7005 // Display->FileDiagnostics(TestString);//test
7006 
7007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
7008  AnsiString TestString1, TestString2; // test
7009 
7010  Track->LNDone2MultiMap.clear();
7011  if(LNPendingList.size() != 1)
7012  {
7013  throw Exception("LNPendingList size not 1 on entry");
7014  }
7015  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
7016  while(!LNPendingList.empty())
7017  {
7018  CurrentElementNumber = LNPendingList.front();
7019  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
7020  int NewElement; // = 2000000000; //marker for unused //not needed after v1.1.4
7021  int H = CurrentElement->HLoc;
7022  int V = CurrentElement->VLoc;
7023  int Tag = CurrentElement->SpeedTag;
7024  if(Tag == 76) // top plat
7025  {
7026  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
7027  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
7028  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
7029  for(int x = 0; x < 25; x++)
7030  {
7031  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
7032  {
7033  LNPendingList.insert(LNPendingList.end(), NewElement);
7034  }
7035  }
7036  }
7037  else if(Tag == 77) // bot plat
7038  {
7039  for(int x = 0; x < 25; x++)
7040  {
7041  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
7042  {
7043  LNPendingList.insert(LNPendingList.end(), NewElement);
7044  }
7045  }
7046  }
7047  else if(Tag == 78) // l plat
7048  {
7049  for(int x = 0; x < 25; x++)
7050  {
7051  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
7052  {
7053  LNPendingList.insert(LNPendingList.end(), NewElement);
7054  }
7055  }
7056  }
7057  else if(Tag == 79) // r plat
7058  {
7059  for(int x = 0; x < 25; x++)
7060  {
7061  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
7062  {
7063  LNPendingList.insert(LNPendingList.end(), NewElement);
7064  }
7065  }
7066  }
7067  else if(Tag == 96) // conc
7068  {
7069  for(int x = 0; x < 28; x++)
7070  {
7071  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
7072  {
7073  LNPendingList.insert(LNPendingList.end(), NewElement);
7074  }
7075  }
7076  }
7077  else if(Tag == 129) // vert footbridge
7078  {
7079  for(int x = 0; x < 8; x++)
7080  {
7081  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
7082  {
7083  LNPendingList.insert(LNPendingList.end(), NewElement);
7084  }
7085  }
7086  }
7087  else if(Tag == 130) // hor footbridge
7088  {
7089  for(int x = 0; x < 8; x++)
7090  {
7091  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
7092  {
7093  LNPendingList.insert(LNPendingList.end(), NewElement);
7094  }
7095  }
7096  }
7097  else if(Tag == 131) // named location
7098  {
7099  for(int x = 0; x < 4; x++)
7100  {
7101  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
7102  {
7103  LNPendingList.insert(LNPendingList.end(), NewElement);
7104  }
7105  }
7106  }
7107  else if(Tag == 145) // v u'pass
7108  {
7109  for(int x = 0; x < 8; x++)
7110  {
7111  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
7112  {
7113  LNPendingList.insert(LNPendingList.end(), NewElement);
7114  }
7115  }
7116  }
7117  else if(Tag == 146) // h u'pass
7118  {
7119  for(int x = 0; x < 8; x++)
7120  {
7121  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
7122  {
7123  LNPendingList.insert(LNPendingList.end(), NewElement);
7124  }
7125  }
7126  }
7127  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
7128 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
7129  if(AddingElements)
7130  {
7131  int HPos, VPos; // not used but needed for FindText function
7132  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
7133  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
7134  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
7135  {
7136  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName;//existing name of CurrentElement
7137  if((ExistingName != "") && (ExistingName != LocationName))
7138  {
7139  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
7140  {} // name not in LocationNameMultiMap, so don't erase from TextVector
7141  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
7142  {
7143  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
7144  {;
7145  } // condition not used
7146  }
7147  }
7148  }
7149  }
7150 
7151  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
7152  // track at that loc
7153  THVPair HVPair(H, V);
7154  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
7155  LNDone2MultiMapEntry.first = HVPair;
7156  LNDone2MultiMapEntry.second = LNPendingList.front();
7157  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
7158  LNPendingList.erase(LNPendingList.begin());
7159  }
7160 
7161 // search all name multimap for same name where corresponding active elements don't appear in
7162 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
7163 
7164  TLocationNameMultiMapIterator SNIterator;
7165  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7166  bool FoundFlag, ErasedFlag = false;
7167 
7168  if(SNRange.first != SNRange.second)
7169  {
7170  SNRange.first--; // now pointing to before the first
7171  SNRange.second--; // now pointing to the last
7172  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
7173  // Same elements are in Done map as in name map
7174  {
7175  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
7176  {
7177  ErasedFlag = true;
7178  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
7179  TVIt->LocationName = "";
7180  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7181  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
7182  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7183  {
7184  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7185  if(FoundFlag)
7186  {
7187  TrackElementAt(20, Position).LocationName = "";
7188  TrackElementAt(21, Position).ActiveTrackElementName = "";
7189  }
7190  }
7191  // erase name in name map
7192 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
7193  }
7194  }
7195  }
7196  if(ErasedFlag)
7198  if(TrackFinished)
7200 // set here as well as in LinkTrack so don't have to link track just because a name added
7201 // if track not finished then will be set when track validated
7202  CheckLocationNameMultiMap(1); // test
7203  Utilities->CallLogPop(562);
7204 }
7205 
7206 // ---------------------------------------------------------------------------
7207 
7208 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
7209 /*
7210  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
7211  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
7212 */
7213 {
7214  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7215  AnsiString(SpeedTag));
7216  if(!NamedLocationElementAt(2, HLoc, VLoc))
7217  {
7218  Utilities->CallLogPop(948);
7219  return false;
7220  }
7221  bool FoundFlag;
7222  int Position = -1;
7223  TIMPair IMPair;
7224 
7225  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
7226  {
7227  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
7228  if(FoundFlag)
7229  {
7230  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
7231  {
7232  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
7233  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
7234  // don't allow duplicates in either list, or processing takes a lot longer
7235  {
7236  FoundElement = MapPos;
7237  Utilities->CallLogPop(563);
7238  return true;
7239  }
7240  }
7241  }
7242  }
7243  else
7244  {
7245  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
7246  if(FoundFlag)
7247  {
7248  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
7249  {
7250  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
7251  {
7252  FoundElement = IMPair.first;
7253  Utilities->CallLogPop(564);
7254  return true;
7255  }
7256  }
7257  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
7258  {
7259  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
7260  {
7261  FoundElement = IMPair.second;
7262  Utilities->CallLogPop(565);
7263  return true;
7264  }
7265  }
7266  }
7267  }
7268  Utilities->CallLogPop(566);
7269  return false;
7270 }
7271 
7272 // ---------------------------------------------------------------------------
7273 
7274 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
7275 /*
7276  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
7277  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
7278  with the new name
7279 */
7280 {
7281  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
7282  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
7283 
7284  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
7285  int HLoc = TrackElement->HLoc;
7286  int VLoc = TrackElement->VLoc;
7287  bool FoundFlag;
7288 
7289  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
7290  // only have timetable names for adjacent platforms & named locations
7291  {
7292  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
7293  if(FoundFlag)
7294  {
7295  TrackElementAt(23, Position).ActiveTrackElementName = Name;
7296  }
7297  }
7298  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
7299 
7300  if(ErrorString != "")
7301  {
7302  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
7303  }
7304  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
7305  CheckLocationNameMultiMap(2); // test
7306  Utilities->CallLogPop(567);
7307 }
7308 
7309 // ---------------------------------------------------------------------------
7310 
7311 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
7312 /*
7313  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
7314 */
7315 {
7316  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
7317  if(LNDone2MultiMap.empty())
7318  {
7319  Utilities->CallLogPop(568);
7320  return false;
7321  }
7322  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
7323 
7324  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
7325  {
7326  if(LNDone2MultiMapIterator->second == MapPos)
7327  {
7328  Utilities->CallLogPop(569);
7329  return true;
7330  }
7331  }
7332  Utilities->CallLogPop(570);
7333  return false;
7334 }
7335 
7336 // ---------------------------------------------------------------------------
7337 
7338 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
7339 /*
7340  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
7341 */
7342 {
7343  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
7344  if(LNPendingList.empty())
7345  {
7346  Utilities->CallLogPop(571);
7347  return false;
7348  }
7349  TLNPendingListIterator LNPendingListIterator;
7350 
7351  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
7352  {
7353  if(*LNPendingListIterator == MapPos)
7354  {
7355  Utilities->CallLogPop(572);
7356  return true;
7357  }
7358  }
7359  Utilities->CallLogPop(573);
7360  return false;
7361 }
7362 
7363 // ---------------------------------------------------------------------------
7364 
7365 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
7366 /*
7367  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
7368 */
7369 {
7370  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7371  THVPair HVPair(HLoc, VLoc);
7372  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
7373  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
7374 
7375  if(TrackMapPtr != TrackMap.end()) // =end() if not found
7376  {
7377  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
7378  {
7379  Utilities->CallLogPop(574);
7380  return true;
7381  }
7382  }
7383  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
7384  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
7385  {
7386  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
7387  {
7388  Utilities->CallLogPop(575);
7389  return true;
7390  }
7391  }
7392  Utilities->CallLogPop(576);
7393  return false;
7394 }
7395 
7396 // ---------------------------------------------------------------------------
7397 
7398 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
7399 {
7400  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
7401  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
7402  {
7403  Utilities->CallLogPop(1953);
7404  return true;
7405  }
7406  Utilities->CallLogPop(1954);
7407  return false;
7408 }
7409 
7410 // ---------------------------------------------------------------------------
7411 
7412 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
7413 /*
7414  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
7415 */
7416 
7417 {
7418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
7419  if(LocationName == "")
7420  {
7421  Utilities->CallLogPop(577);
7422  return false;
7423  }
7424 // new for v0.2b
7425 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
7427  {
7428  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
7429  ActiveTrackElementNameMap.clear();
7430  for(unsigned int x = 0; x < TrackVector.size(); x++)
7431  {
7432  if((TrackVector.at(x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackVector.at(x).ActiveTrackElementName))
7433  == ContinuationNameMap.end())
7434  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
7435  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
7436  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
7437  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
7438  }
7439  }
7441  }
7442  Utilities->CallLogPop(578);
7443  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
7444 // end of new section
7445 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
7446 }
7447 
7448 // ---------------------------------------------------------------------------
7449 
7450 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
7451 /*
7452  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
7453  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
7454  new names in the vectors.
7455 */
7456 {
7457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
7458  bool FoundFlag, ErasedFlag = false;
7459  TLocationNameMultiMapIterator SNIterator;
7460  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7461 
7462  if(SNRange.first != SNRange.second)
7463  {
7464  ErasedFlag = true;
7465  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
7466  {
7467  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
7468  TVIt->LocationName = "";
7469  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7470  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
7471  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7472  {
7473  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7474  if(FoundFlag)
7475  {
7476  TrackElementAt(25, Position).LocationName = "";
7477  TrackElementAt(26, Position).ActiveTrackElementName = "";
7478  }
7479  }
7480  }
7481  }
7482  if(ErasedFlag)
7484  CheckLocationNameMultiMap(3); // test
7485  Utilities->CallLogPop(579);
7486 }
7487 
7488 // ---------------------------------------------------------------------------
7489 
7490 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
7491 /*
7492  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
7493  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
7494  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
7495  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
7496  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
7497  naming up to date with the deletion or insertion.
7498 */
7499 {
7500  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
7501  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
7502  LNPendingList.clear();
7503  AnsiString LocationName;
7504  int MapPos;
7505 
7506  if(SpeedTag == 76) // top plat
7507  {
7508  for(int x = 0; x < 25; x++)
7509  {
7510  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
7511  {
7512  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7513  EnterLocationName(3, LocationName, true);
7514  break;
7515  }
7516  }
7517  }
7518  else if(SpeedTag == 77) // bot plat
7519  {
7520  for(int x = 0; x < 25; x++)
7521  {
7522  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
7523  {
7524  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7525  EnterLocationName(4, LocationName, true);
7526  break;
7527  }
7528  }
7529  }
7530  else if(SpeedTag == 78) // l plat
7531  {
7532  for(int x = 0; x < 25; x++)
7533  {
7534  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
7535  {
7536  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7537  EnterLocationName(5, LocationName, true);
7538  break;
7539  }
7540  }
7541  }
7542  else if(SpeedTag == 79) // r plat
7543  {
7544  for(int x = 0; x < 25; x++)
7545  {
7546  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
7547  {
7548  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7549  EnterLocationName(6, LocationName, true);
7550  break;
7551  }
7552  }
7553  }
7554  else if(SpeedTag == 96) // conc
7555  {
7556  for(int x = 0; x < 28; x++)
7557  {
7558  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
7559  {
7560  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7561  EnterLocationName(7, LocationName, true);
7562  break;
7563  }
7564  }
7565  }
7566  else if(SpeedTag == 129) // vert footbridge
7567  {
7568  for(int x = 0; x < 8; x++)
7569  {
7570  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
7571  {
7572  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7573  EnterLocationName(8, LocationName, true);
7574  break;
7575  }
7576  }
7577  }
7578  else if(SpeedTag == 130) // hor footbridge
7579  {
7580  for(int x = 0; x < 8; x++)
7581  {
7582  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
7583  {
7584  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7585  EnterLocationName(9, LocationName, true);
7586  break;
7587  }
7588  }
7589  }
7590  else if(SpeedTag == 145) // vert u'pass
7591  {
7592  for(int x = 0; x < 8; x++)
7593  {
7594  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
7595  {
7596  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7597  EnterLocationName(11, LocationName, true);
7598  break;
7599  }
7600  }
7601  }
7602  else if(SpeedTag == 146) // hor u'pass
7603  {
7604  for(int x = 0; x < 8; x++)
7605  {
7606  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
7607  {
7608  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7609  EnterLocationName(12, LocationName, true);
7610  break;
7611  }
7612  }
7613  }
7614  else if(SpeedTag == 131) // named location
7615  {
7616  for(int x = 0; x < 4; x++)
7617  {
7618  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
7619  {
7620  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7621  EnterLocationName(10, LocationName, true);
7622  break;
7623  }
7624  }
7625  }
7626 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
7627  Utilities->CallLogPop(580);
7628 }
7629 
7630 // ---------------------------------------------------------------------------
7631 
7632 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
7633 /*
7634  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
7635  true if a LocationName is found, and also returns the name and the adjusted vector position.
7636 */
7637 {
7638  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7639  AnsiString(SpeedTag));
7640  bool FoundFlag;
7641  TIMPair IMPair;
7642  TTrackVectorIterator TempElement;
7643  int Position;
7644 
7645  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
7646  if(FoundFlag)
7647  {
7648  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
7649  {
7650  TempElement = InactiveTrackVector.begin() + IMPair.first;
7651  if(TempElement->LocationName != "")
7652  {
7653  LocationName = TempElement->LocationName;
7654  FoundElement = IMPair.first;
7655  Utilities->CallLogPop(581);
7656  return true;
7657  }
7658  }
7659  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
7660  {
7661  TempElement = InactiveTrackVector.begin() + IMPair.second;
7662  if(TempElement->LocationName != "")
7663  {
7664  LocationName = TempElement->LocationName;
7665  FoundElement = IMPair.second;
7666  Utilities->CallLogPop(582);
7667  return true;
7668  }
7669  }
7670  }
7671 
7672  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
7673  if(FoundFlag)
7674  {
7675  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
7676  {
7677  TempElement = TrackVector.begin() + Position;
7678  if(TempElement->LocationName != "")
7679  {
7680  LocationName = TempElement->LocationName;
7681  FoundElement = -1 - Position;
7682  Utilities->CallLogPop(583);
7683  return true;
7684  }
7685  }
7686  }
7687  Utilities->CallLogPop(584);
7688  return false;
7689 }
7690 
7691 // ---------------------------------------------------------------------------
7692 
7693 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
7694 {
7695 // check quantity in map & vectors match
7696  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
7697  unsigned int Count = 0;
7698 
7699  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
7700  {
7701  Utilities->CallLogPop(2059);
7702  return;
7703  }
7704 
7705  AnsiString SName, TName, ErrorString;
7706 
7707  for(unsigned int x = 0; x < TrackVector.size(); x++)
7708  {
7709  if(TrackVector.at(x).FixedNamedLocationElement)
7710  {
7711  if(TrackVector.at(x).TrackType != FootCrossing)
7712  {
7713  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
7714  AnsiString(Caller));
7715  }
7716  Count++;
7717  }
7718  }
7719  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7720  {
7721  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
7722  {
7723  if((InactiveTrackVector.at(x).TrackType != Platform) && (InactiveTrackVector.at(x).TrackType != NamedNonStationLocation) &&
7724  (InactiveTrackVector.at(x).TrackType != Concourse))
7725  {
7726  throw Exception
7727  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
7728  AnsiString(Caller));
7729  }
7730  Count++;
7731  }
7732  }
7733  if(LocationNameMultiMap.size() != Count)
7734  {
7735  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
7736  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
7737  }
7738 
7739 // check all entries in both vectors match entries in name multimap
7741 
7742  for(unsigned int x = 0; x < TrackVector.size(); x++)
7743  {
7744  if(TrackVector.at(x).FixedNamedLocationElement)
7745  {
7746  SName = TrackVector.at(x).LocationName;
7747  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
7748  if(ErrorString != "")
7749  {
7750  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
7751  }
7752  if(SNIt->second != -1 - (int)x)
7753  {
7754  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
7755  AnsiString(Caller));
7756  }
7757  }
7758  // check corresponding platform for all Timetable entries that aren't empty
7759  TName = TrackVector.at(x).ActiveTrackElementName;
7760  TIMPair IMPair;
7761  bool FoundFlag = false;
7762  if(TName != "")
7763  {
7764  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc, FoundFlag);
7765  if(FoundFlag)
7766  {
7767  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
7769  {
7770  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
7771  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
7772  }
7773  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
7774  {
7775  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) +
7776  " & V " + AnsiString(TrackVector.at(x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
7777  AnsiString(Caller));
7778  }
7779  }
7780  else
7781  {
7782  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
7783  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
7784  }
7785  }
7786  }
7787  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7788  {
7789  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
7790  {
7791  SName = InactiveTrackVector.at(x).LocationName;
7792  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
7793  if(ErrorString != "")
7794  {
7795  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
7796  }
7797  if(SNIt->second != (int)x)
7798  {
7799  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
7800  AnsiString(Caller));
7801  }
7802  }
7803  }
7804  Utilities->CallLogPop(585);
7805 }
7806 
7807 // ---------------------------------------------------------------------------
7808 
7810  AnsiString &ErrorString)
7811 {
7812 /*
7813  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
7814  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
7815  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
7816 */
7817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
7818  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
7819  ErrorString = "";
7820  bool FoundFlag = false;
7821  TLocationNameMultiMapIterator SNIterator;
7822  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7823 
7824  if(SNRange.first == SNRange.second)
7825  {
7826  ErrorString = "Error, Name " + LocationName + " not found in map";
7827  Utilities->CallLogPop(586);
7828  return SNRange.first;
7829  }
7830  else
7831  {
7832  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
7833  {
7834  if(SNIterator->second < 0)
7835  {
7836  int TVPos = -1 - SNIterator->second;
7837  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
7838  if(TVIt == TrackElement)
7839  {
7840  FoundFlag = true;
7841  Utilities->CallLogPop(587);
7842  return SNIterator;
7843  }
7844  }
7845  else
7846  {
7847  int ITVPos = SNIterator->second;
7848  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
7849  if(ITVIt == TrackElement)
7850  {
7851  FoundFlag = true;
7852  Utilities->CallLogPop(588);
7853  return SNIterator;
7854  }
7855  }
7856  }
7857  }
7858  if(!FoundFlag)
7859  ErrorString = "Error, Name " + LocationName + " found but not at required element";
7860  Utilities->CallLogPop(589);
7861  return SNIterator;
7862 }
7863 
7864 // ---------------------------------------------------------------------------
7865 
7866 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
7867 {
7868 /*
7869  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
7870  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
7871 */
7872  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
7873  TLocationNameMultiMapEntry LocationNameEntry;
7874 
7875  LocationNameEntry.first = NewName;
7876  LocationNameEntry.second = SNIterator->second;
7877  LocationNameMultiMap.erase(SNIterator);
7878  LocationNameMultiMap.insert(LocationNameEntry);
7879  Utilities->CallLogPop(590);
7880 }
7881 
7882 // ---------------------------------------------------------------------------
7883 
7885 {
7886 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
7887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
7888  if(Position < 0) // footcrossing
7889  {
7890  int TruePos = -1 - Position;
7891  // new check at v0.2b
7892  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
7893  {
7894  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
7895  }
7896  Utilities->CallLogPop(591);
7897  return (TrackVector.begin() + TruePos);
7898  }
7899  else
7900  {
7901  // new check at v0.2b
7902  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
7903  {
7904  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
7905  }
7906  Utilities->CallLogPop(592);
7907  return (InactiveTrackVector.begin() + Position);
7908  }
7909 }
7910 
7911 // ---------------------------------------------------------------------------
7912 
7913 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
7914 {
7915 /*
7916  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
7917  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
7918  LocationNameMultiMap.
7919 */
7920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
7921  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
7922  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
7923 
7924  if(!InactiveTrack2MultiMap.empty())
7925  {
7926  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
7927  InactiveTrack2MultiMapIterator++)
7928  {
7929  if(InactiveTrack2MultiMapIterator->second > VecPos)
7930  InactiveTrack2MultiMapIterator->second--;
7931  // can't be == VecPos as that position erased
7932  }
7933  }
7934  if(!LocationNameMultiMap.empty())
7935  {
7936  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
7937  LocationNameMultiMapIterator++)
7938  {
7939  if(LocationNameMultiMapIterator->second < 0)
7940  continue; // deal with TrackVectors separately
7941  if(LocationNameMultiMapIterator->second > (int)VecPos)
7942  LocationNameMultiMapIterator->second--;
7943  }
7944  }
7945  Utilities->CallLogPop(593);
7946 }
7947 
7948 // ---------------------------------------------------------------------------
7949 
7950 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
7951 {
7952 /*
7953  After an element has been erased from the track vector, all the later elements are moved down one. This function
7954  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
7955  LocationNameMultiMap.
7956 */
7957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
7958  TTrackMapIterator TrackMapIterator;
7959  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
7960 
7961  if(!TrackMap.empty())
7962  {
7963  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
7964  {
7965  if(TrackMapIterator->second > VecPos)
7966  TrackMapIterator->second--;
7967  // can't be == VecPos as that position erased
7968  }
7969  }
7970  if(!LocationNameMultiMap.empty())
7971  {
7972  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
7973  LocationNameMultiMapIterator++)
7974  {
7975  if(LocationNameMultiMapIterator->second >= 0)
7976  continue; // deal with InactiveTrackVectors separately
7977  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
7978  // Val -1 -2 -3 -4 -5 -6 -7 -8
7979  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
7980  LocationNameMultiMapIterator->second++;
7981  }
7982  }
7983  for(unsigned int x = 0; x < TrackVector.size(); x++)
7984  {
7985  TTrackElement &TkEl = TrackVector.at(x); // no need to check so use this to speed up
7986  if(TkEl.TrackType == GapJump)
7987  {
7988  // position 0 is the gap
7989  if(TkEl.Conn[0] == int(VecPos))
7990  {
7991  TkEl.Conn[0] = -1; // connected to a deleted gap
7992  continue;
7993  }
7994  if(TkEl.Conn[0] > int(VecPos))
7995  TkEl.Conn[0]--;
7996  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
7997  {
7998  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
7999  TkEl.Conn[0] = -1;
8000  }
8001  }
8002  }
8003  Utilities->CallLogPop(1433);
8004 }
8005 
8006 // ---------------------------------------------------------------------------
8007 
8009 /*
8010  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
8011  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
8012  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
8013 */
8014 {
8015  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
8016  LocationNameMultiMap.clear();
8017  TLocationNameMultiMapEntry LocationNameEntry;
8018  TTrackElement TrackElement;
8019 
8020  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
8021  {
8022  TrackElement = TrackVector.at(TVPos);
8023  if(TrackElement.FixedNamedLocationElement)
8024  {
8025  LocationNameEntry.first = TrackElement.LocationName;
8026  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
8027  LocationNameMultiMap.insert(LocationNameEntry);
8028  }
8029  }
8030 
8031  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
8032  {
8033  TrackElement = InactiveTrackVector.at(ITVPos);
8034  if(TrackElement.FixedNamedLocationElement)
8035  {
8036  LocationNameEntry.first = TrackElement.LocationName;
8037  LocationNameEntry.second = ITVPos;
8038  LocationNameMultiMap.insert(LocationNameEntry);
8039  }
8040  }
8041  Utilities->CallLogPop(594);
8042 }
8043 
8044 // ---------------------------------------------------------------------------
8045 
8047  // Return true if there is a named location present in the railway
8048  // ignores lone footcrossings, can't name these on their own & track won't link if there are any
8049 {
8050  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
8051  TTrackVectorIterator ITVI;
8052 
8053  if(InactiveTrackVector.empty())
8054  {
8055  Utilities->CallLogPop(1343);
8056  return false;
8057  }
8058  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
8059  {
8060  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
8061  {
8062  Utilities->CallLogPop(1404);
8063  return true;
8064  }
8065  }
8066  Utilities->CallLogPop(1344);
8067  return false;
8068 }
8069 
8070 // ---------------------------------------------------------------------------
8071 
8073 /*
8074  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
8075 */
8076 {
8077  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
8078 // ResetDistanceElements(6);
8079  for(unsigned int x = 0; x < TrackVector.size(); x++)
8080  {
8081  TTrackElement &TE = TrackElementAt(718, x);
8084  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
8085  {
8088  }
8089  }
8090 /* old function
8091  if((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == Crossover) || (TrackVector.at(x).TrackType == Bridge))
8092  {
8093  SetOneDefaultTrackLength(2, TrackVector.at(x), 0);
8094  SetOneDefaultTrackLength(3, TrackVector.at(x), 2);
8095  }
8096  else
8097  {
8098  SetOneDefaultTrackLength(4, TrackVector.at(x), 0);
8099  }
8100  }
8101 */
8102  Utilities->CallLogPop(617);
8103 }
8104 
8105 // ---------------------------------------------------------------------------
8106 
8107 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
8108  // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
8109 {
8110  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
8111  for(unsigned int x = 0; x < TrackVector.size(); x++)
8112  {
8113  TTrackElement TempElement = TrackVector.at(x);
8114  if(TempElement.Length01 > -1)
8115  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
8116  if(TempElement.Length23 > -1)
8117  MarkOneLength(2, TempElement, false, Disp);
8118  }
8119  Disp->Update();
8120  Utilities->CallLogPop(618);
8121 }
8122 
8123 // ---------------------------------------------------------------------------
8124 
8125 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
8126 /*
8127  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
8128  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
8129  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
8130  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
8131  track as indicated by FirstTrack (true for track01 & false for track23).
8132 */
8133 {
8134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
8135  AnsiString((short)FirstTrack));
8136  bool LengthDifferent = false, SpeedDifferent = false;
8137 
8138  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
8139  {
8140  Utilities->CallLogPop(619);
8141  return;
8142  }
8143 
8144  int EXArray[16][2] =
8145  {{4, 6}, {2, 8}, // horizontal & vertical
8146  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
8147  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
8148  {1, 9}, {3, 7}}; // forward & reverse diagonals
8149 
8150  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
8151  Graphics::TBitmap *Bitmap;
8152 
8153  if(FirstTrack)
8154  {
8155  InLink = TrackElement.Link[0];
8156  OutLink = TrackElement.Link[1];
8157  }
8158  else
8159  {
8160  InLink = TrackElement.Link[2];
8161  OutLink = TrackElement.Link[3];
8162  }
8163 
8164  for(int x = 0; x < 16; x++)
8165  {
8166  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
8167  Index = x;
8168  }
8169  if(Index == -1)
8170  {
8171  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
8172  }
8173 
8174 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
8175  the graphic for each of which is different because of the shape of the overbridge. The basic
8176  entry/exit value is computed above, and this used to select only from elements with that entry/exit
8177  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
8178  int BrEXArray[24][2] = {
8179  {4,6},{2,8},{1,9},{3,7},
8180  {1,9},{3,7},{1,9},{3,7},
8181  {2,8},{4,6},{2,8},{4,6}
8182 */
8183  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8184  {
8185  if(Index == 1)
8186  {
8187  if(TrackElement.SpeedTag == 49)
8188  BrNum = 1 + 16;
8189  else if(TrackElement.SpeedTag == 54)
8190  BrNum = 8 + 16;
8191  else if(TrackElement.SpeedTag == 55)
8192  BrNum = 10 + 16;
8193  }
8194  else if(Index == 0)
8195  {
8196  if(TrackElement.SpeedTag == 48)
8197  BrNum = 0 + 16;
8198  else if(TrackElement.SpeedTag == 58)
8199  BrNum = 11 + 16;
8200  else if(TrackElement.SpeedTag == 59)
8201  BrNum = 9 + 16;
8202  }
8203  else if(Index == 14)
8204  {
8205  if(TrackElement.SpeedTag == 50)
8206  BrNum = 2 + 16;
8207  else if(TrackElement.SpeedTag == 52)
8208  BrNum = 4 + 16;
8209  else if(TrackElement.SpeedTag == 57)
8210  BrNum = 6 + 16;
8211  }
8212  else if(Index == 15)
8213  {
8214  if(TrackElement.SpeedTag == 51)
8215  BrNum = 3 + 16;
8216  else if(TrackElement.SpeedTag == 53)
8217  BrNum = 7 + 16;
8218  else if(TrackElement.SpeedTag == 56)
8219  BrNum = 5 + 16;
8220  }
8221  }
8222 
8223  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8224  GrNum = BrNum;
8225  else
8226  GrNum = Index;
8227 
8228  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
8229  {
8230  if(GrNum > 15) // underbridge
8231  {
8232  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
8233  }
8234  else
8235  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
8236 
8237  if(TrackElement.SpeedTag == 64)
8238  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8239  if(TrackElement.SpeedTag == 65)
8241  if(TrackElement.SpeedTag == 66)
8243  if(TrackElement.SpeedTag == 67)
8245 
8246  if(TrackElement.SpeedTag == 80)
8247  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
8248  if(TrackElement.SpeedTag == 81)
8250  if(TrackElement.SpeedTag == 82)
8252  if(TrackElement.SpeedTag == 83)
8254  if(TrackElement.SpeedTag == 84)
8256  if(TrackElement.SpeedTag == 85)
8258  if(TrackElement.SpeedTag == 86)
8260  if(TrackElement.SpeedTag == 87)
8262 
8263  if(TrackElement.SpeedTag == 129)
8264  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
8265  if(TrackElement.SpeedTag == 130)
8267  }
8268 
8269  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
8270  {
8271  if(GrNum > 15) // underbridge
8272  {
8273  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
8274  }
8275  else
8276  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
8277 
8278  if(TrackElement.SpeedTag == 64)
8279  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8280  if(TrackElement.SpeedTag == 65)
8281  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
8282  if(TrackElement.SpeedTag == 66)
8283  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
8284  if(TrackElement.SpeedTag == 67)
8285  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
8286 
8287  if(TrackElement.SpeedTag == 80)
8288  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8289  if(TrackElement.SpeedTag == 81)
8290  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
8291  if(TrackElement.SpeedTag == 82)
8292  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
8293  if(TrackElement.SpeedTag == 83)
8294  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
8295  if(TrackElement.SpeedTag == 84)
8296  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
8297  if(TrackElement.SpeedTag == 85)
8298  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
8299  if(TrackElement.SpeedTag == 86)
8300  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
8301  if(TrackElement.SpeedTag == 87)
8302  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
8303 
8304  if(TrackElement.SpeedTag == 129)
8305  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
8306  if(TrackElement.SpeedTag == 130)
8307  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
8308  }
8309 
8310  else // SpeedDifferent only: red - use non sig graphics
8311  {
8312  if(GrNum > 15) // underbridge
8313  {
8314  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
8315  }
8316  else
8317  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
8318 
8319  if(TrackElement.SpeedTag == 64)
8320  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8321  if(TrackElement.SpeedTag == 65)
8323  if(TrackElement.SpeedTag == 66)
8325  if(TrackElement.SpeedTag == 67)
8327 
8328  if(TrackElement.SpeedTag == 80)
8329  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8330  if(TrackElement.SpeedTag == 81)
8332  if(TrackElement.SpeedTag == 82)
8334  if(TrackElement.SpeedTag == 83)
8336  if(TrackElement.SpeedTag == 84)
8338  if(TrackElement.SpeedTag == 85)
8340  if(TrackElement.SpeedTag == 86)
8342  if(TrackElement.SpeedTag == 87)
8344 
8345  if(TrackElement.SpeedTag == 129)
8346  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
8347  if(TrackElement.SpeedTag == 130)
8349  }
8350 
8351  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
8352  Utilities->CallLogPop(620);
8353 }
8354 
8355 // ---------------------------------------------------------------------------
8356 
8357 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
8358 /* FirstTrack = LinkPos's 0 & 1
8359  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
8360 */
8361 {
8362  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
8363  AnsiString((short)FirstTrack));
8364  LengthDifferent = false;
8365  SpeedDifferent = false;
8366  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
8367  {
8368  if(TrackElement.Length01 != DefaultTrackLength)
8369  {
8370  LengthDifferent = true;
8371  }
8372  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8373  {
8374  SpeedDifferent = true;
8375  }
8376  if(LengthDifferent || SpeedDifferent)
8377  {
8378  Utilities->CallLogPop(625);
8379  return false;
8380  }
8381  Utilities->CallLogPop(626);
8382  return true;
8383  }
8384 
8385  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
8386  {
8387  if(TrackElement.Length23 != DefaultTrackLength)
8388  {
8389  LengthDifferent = true;
8390  }
8391  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
8392  {
8393  SpeedDifferent = true;
8394  }
8395  if(LengthDifferent || SpeedDifferent)
8396  {
8397  Utilities->CallLogPop(627);
8398  return false;
8399  }
8400  Utilities->CallLogPop(628);
8401  return true;
8402  }
8403 
8404  else // any other 1 track element, including platforms being present
8405  {
8406  if(TrackElement.Length01 != DefaultTrackLength)
8407  {
8408  LengthDifferent = true;
8409  }
8410  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8411  {
8412  SpeedDifferent = true;
8413  }
8414  if(LengthDifferent || SpeedDifferent)
8415  {
8416  Utilities->CallLogPop(629);
8417  return false;
8418  }
8419  Utilities->CallLogPop(630);
8420  return true;
8421  }
8422 }
8423 
8424 // ---------------------------------------------------------------------------
8425 
8426 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
8427  // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
8428 {
8429  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
8430  AnsiString(VLoc));
8431  bool FoundFlag;
8432  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
8433 
8434  if(!FoundFlag)
8435  {
8436  Utilities->CallLogPop(633);
8437  return false;
8438  }
8439  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
8440  {
8441  Utilities->CallLogPop(634);
8442  return true; // only need to check first since if second is a platform the the first must be too
8443  }
8444  else
8445  {
8446  Utilities->CallLogPop(635);
8447  return false;
8448  }
8449 }
8450 
8451 // ---------------------------------------------------------------------------
8452 
8453 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
8454  // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
8455 {
8456  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
8457  AnsiString(VLoc));
8458  bool FoundFlag;
8459  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
8460 
8461  if(!FoundFlag)
8462  {
8463  Utilities->CallLogPop(636);
8464  return false;
8465  }
8467  {
8468  Utilities->CallLogPop(637);
8469  return true; // only need to check first since only one used for NamedNonStationLocations
8470  }
8471  else
8472  {
8473  Utilities->CallLogPop(638);
8474  return false;
8475  }
8476 }
8477 
8478 // ---------------------------------------------------------------------------
8479 
8481 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
8482  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
8483  the front of train stop points for each direction.
8484  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
8485  end (unless buffers at one or both ends in which case stop points are the end elements).
8486  Note that for a single element the stop point is the element itself (formula doesn't apply).
8487  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
8488  repeating the procedure for every element. At the end all unused values are returned to -1.
8489  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
8490 */
8491 {
8492  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
8493  TTrackElement TempElement, StartElement;
8494  AnsiString TempName;
8495  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
8496  bool ForwardSet, ReverseSet;
8497 
8498  for(unsigned int x = 0; x < TrackVector.size(); x++)
8499  {
8500  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
8501  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
8502  }
8503  for(unsigned int x = 0; x < TrackVector.size(); x++)
8504  {
8505  ForwardSet = false;
8506  ReverseSet = false;
8507  TempElement = TrackVector.at(x);
8508  VecPos = x;
8509  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
8510  // 2nd condition incl so don't re-examine elements with stop links set to 5
8511  {
8512  TempName = TempElement.ActiveTrackElementName;
8513  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
8514  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
8515  // an element linked at both ends where both links are also named elements
8516  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
8517  {
8518  continue; // looking for an end element so skip this one
8519  }
8520  else // reached one end
8521  {
8522  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
8523  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
8524  // single named element linked at both ends
8525  {
8526  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
8527  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
8528  continue;
8529  }
8530  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
8531  // single named buffer element (LinkPos 1 is the non-buffer end)
8532  {
8533  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
8534  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
8535  continue;
8536  }
8537  else
8538  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
8539  // and platforms always on straight (conns 0 & 1) section of points
8540  {
8541  for(int y = 0; y < 2; y++)
8542  {
8543  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
8544  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
8545 /* TTrackElement Temp1 = TempElement;
8546  ***********New section, compiles but not checked - does bit below need to be else if?
8547  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
8548  {
8549  //search along Dir direction until find other end, skip if Dir facing buffer end
8550  int NewDir = Dir;
8551  int NewVecPos;
8552  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
8553  {
8554  NewVecPos = Temp1.Conn[NewDir];
8555  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
8556  Temp1 = TrackElementAt(601, NewVecPos);
8557  }
8558  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
8559  {
8560  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
8561  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
8562  }
8563  }
8564  ***************
8565 */
8566  // end may be linked at both ends but only one link named, or buffer with linked element named
8567  // if a buffer then the named linkpos has to be 1
8568  // already dealt with all types of single element so at least 2 linked named element
8569  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
8570  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
8571  {
8572  StartElement = TempElement;
8573  StartVecPos = VecPos;
8574  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
8575  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
8576  EntryPos = 1 - Dir;
8577  StartEntryPos = 1 - Dir;
8578  Count = 1;
8579  // work along named elements until find the other end
8580  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
8581  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
8582  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
8583  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
8584  // all stop link pos's are set to 5
8585  {
8586  VecPos = TempElement.Conn[1 - EntryPos];
8587  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
8588  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
8589  EntryPos = TempEntryPos;
8590  Count++;
8591  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
8592  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
8593  }
8594  // here when reached other end, maybe buffers, continuation or last named linked element
8595  if(TrackElementAt(57, VecPos).TrackType == Buffers)
8596  // terminal station, set end elements as stop elements
8597  {
8598  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
8599  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
8600  continue;
8601  }
8602  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
8603  // terminal station, set end elements as stop elements
8604  {
8605  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
8606  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
8607  continue;
8608  }
8609  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
8610  // NonStationLocation so set end elements as stop elements
8611  {
8612  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
8613  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
8614  continue;
8615  }
8616  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
8617  ForwardNumber = ((Count + 1) / 2) + 1;
8618  ReverseNumber = (Count - ForwardNumber) + 1;
8619  Count = 1; // starting value
8620  EntryPos = 1 - Dir;
8621  TempElement = StartElement;
8622  VecPos = StartVecPos;
8623  if(Count == ForwardNumber)
8624  {
8625  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
8626  ForwardSet = true;
8627  }
8628  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
8629  {
8630  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
8631  ReverseSet = true;
8632  }
8633  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
8634  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
8635  {
8636  VecPos = TempElement.Conn[1 - EntryPos];
8637  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
8638  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
8639  EntryPos = TempEntryPos;
8640  Count++;
8641  if(Count == ForwardNumber)
8642  {
8643  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
8644  ForwardSet = true;
8645  }
8646  if(Count == ReverseNumber)
8647  {
8648  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
8649  ReverseSet = true;
8650  }
8651  }
8652  }
8653  }
8654  }
8655  }
8656  }
8657  }
8658  for(unsigned int x = 0; x < TrackVector.size(); x++)
8659  {
8660  if(TrackVector.at(x).StationEntryStopLinkPos1 == 5)
8661  {
8662  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
8663  }
8664  if(TrackVector.at(x).StationEntryStopLinkPos2 == 5)
8665  {
8666  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
8667  }
8668  }
8669  Utilities->CallLogPop(639);
8670 }
8671 
8672 // ---------------------------------------------------------------------------
8673 
8674 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
8675 {
8676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
8677  TTrackElement Next;
8678 
8680  while(ReturnNextInactiveTrackElement(1, Next))
8681  {
8682  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
8683  {
8684  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
8685  // need striped graphics
8686  {
8687  if(Next.SpeedTag == 76)
8688  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
8689  else if(Next.SpeedTag == 77)
8690  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
8691  else if(Next.SpeedTag == 78)
8692  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
8693  else if(Next.SpeedTag == 79)
8694  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
8695  else if(Next.SpeedTag == 96)
8696  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
8697  else if(Next.SpeedTag == 131)
8698  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
8699  }
8700  else
8701  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
8702  }
8703  }
8704 
8705  NextTrackElementPtr = TrackVector.begin();
8706  while(ReturnNextTrackElement(1, Next))
8707  {
8708  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
8709  {
8710  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
8711  {
8712  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
8713  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
8714  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
8715  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
8716  }
8717  else
8718  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
8719  }
8720  }
8721  Disp->Update();
8722  Utilities->CallLogPop(640);
8723 }
8724 
8725 // ---------------------------------------------------------------------------
8726 
8727 void TTrack::PlotSmallRedGap(int Caller)
8728 {
8729  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
8731  Utilities->CallLogPop(1346);
8732 }
8733 
8734 // ---------------------------------------------------------------------------
8735 
8736 void TTrack::TrackClear(int Caller)
8737 {
8738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
8739  TrackVector.clear();
8740  InactiveTrackVector.clear();
8741  TrackMap.clear();
8743  if(TextHandler->TextVector.size() == 0)
8744  {
8745  Display->DisplayOffsetH = 0;
8746  Display->DisplayOffsetV = 0;
8753  HLocMin = 2000000000;
8754  HLocMax = -2000000000;
8755  VLocMin = 2000000000;
8756  VLocMax = -2000000000;
8757  }
8758  else
8759  CalcHLocMinEtc(4);
8760  Utilities->CallLogPop(1347);
8761 }
8762 
8763 // ---------------------------------------------------------------------------
8764 
8765 void TTrack::CalcHLocMinEtc(int Caller)
8766 {
8767  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
8768  HLocMin = 2000000000;
8769  VLocMin = 2000000000;
8770  HLocMax = -2000000000;
8771  VLocMax = -2000000000;
8772  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
8773  {
8774  if(TrackVector.at(x).SpeedTag == 0)
8775  continue; // skip erase elements or would interfere with Min & Max values
8776  if(TrackVector.at(x).HLoc - 1 < HLocMin)
8777  HLocMin = TrackVector.at(x).HLoc - 1; // add one all round
8778  if(TrackVector.at(x).HLoc + 1 > HLocMax)
8779  HLocMax = TrackVector.at(x).HLoc + 1;
8780  if(TrackVector.at(x).VLoc - 1 < VLocMin)
8781  VLocMin = TrackVector.at(x).VLoc - 1;
8782  if(TrackVector.at(x).VLoc + 1 > VLocMax)
8783  VLocMax = TrackVector.at(x).VLoc + 1;
8784  }
8785  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
8786  {
8787  if(InactiveTrackVector.at(x).SpeedTag == 0)
8788  continue; // shouldn't be any inactive erase elements but include anyway
8789  if(InactiveTrackVector.at(x).HLoc - 1 < HLocMin)
8790  HLocMin = InactiveTrackVector.at(x).HLoc - 1; // add one all round
8791  if(InactiveTrackVector.at(x).HLoc + 1 > HLocMax)
8792  HLocMax = InactiveTrackVector.at(x).HLoc + 1;
8793  if(InactiveTrackVector.at(x).VLoc - 1 < VLocMin)
8794  VLocMin = InactiveTrackVector.at(x).VLoc - 1;
8795  if(InactiveTrackVector.at(x).VLoc + 1 > VLocMax)
8796  VLocMax = InactiveTrackVector.at(x).VLoc + 1;
8797  }
8798  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
8799  {
8800 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
8801  will fail as x will exceed the maximum value
8802  if(TextHandler->TextPtrAt(, x)->TextString == "")
8803  {
8804  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
8805  }
8806 */
8807  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
8808  if((TextH / 16) - 1 < HLocMin)
8809  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
8810  if((TextH / 16) + 1 > HLocMax)
8811  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
8812  if((TextV / 16) - 1 < VLocMin)
8813  VLocMin = (TextV / 16) - 1;
8814  if((TextV / 16) + 1 > VLocMax)
8815  VLocMax = (TextV / 16) + 1;
8816  }
8817  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
8818  {
8819  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
8820  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
8821  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
8822  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
8823  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
8824  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
8825  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
8826  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
8827  }
8828 
8829  Utilities->CallLogPop(641);
8830 }
8831 
8832 // ---------------------------------------------------------------------------
8833 
8834 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
8835  bool &UserGraphicFoundFlag)
8836 {
8837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
8838  TUserGraphicVector::iterator UserGraphicPtr;
8839 
8840  UserGraphicFoundFlag = false;
8841  if(!UserGraphicVector.empty())
8842  {
8843  int x = UserGraphicVector.size();
8844  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
8845  {
8846  x--;
8847  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
8848  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
8849  {
8850  UserGraphicItem = x;
8851  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
8852  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
8853  UserGraphicFoundFlag = true;
8854  Utilities->CallLogPop(2177);
8855  return;
8856  } // if ....
8857  } // for UserGraphicPtr...
8858  } // if !UserGraphicVector...
8859  Utilities->CallLogPop(2197);
8860 }
8861 
8862 // ---------------------------------------------------------------------------
8863 
8865 {
8866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
8867  TrackElement.LogTrack(11));
8868  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
8869  int SpeedTag = TrackElement.SpeedTag;
8870 
8871  if(SpeedTag < 1)
8872  {
8873  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
8874  }
8875  switch(SpeedTag)
8876  {
8877  case 76: // t platform
8878  GraphicOutput = RailGraphics->gl76Striped;
8879  break;
8880 
8881  case 77: // h platform
8882  GraphicOutput = RailGraphics->bm77Striped;
8883  break;
8884 
8885  case 78: // v platform
8886  GraphicOutput = RailGraphics->bm78Striped;
8887  break;
8888 
8889  case 79: // r platform
8890  GraphicOutput = RailGraphics->gl79Striped;
8891  break;
8892 
8893  case 96: // concourse
8894  GraphicOutput = RailGraphics->ConcourseStriped;
8895  break;
8896 
8897  case 129: // v footbridge
8898  GraphicOutput = RailGraphics->gl129Striped;
8899  break;
8900 
8901  case 130: // h footbridge
8902  GraphicOutput = RailGraphics->gl130Striped;
8903  break;
8904 
8905  case 131: // non-station named loc
8906  GraphicOutput = RailGraphics->bmNameStriped;
8907  break;
8908 
8909  case 145: // v u'pass
8910  GraphicOutput = RailGraphics->gl145Striped;
8911  break;
8912 
8913  case 146: // h u'pass
8914  GraphicOutput = RailGraphics->gl146Striped;
8915  break;
8916 
8917  default:
8918  GraphicOutput = TrackElement.GraphicPtr;
8919  break;
8920  }
8921  Utilities->CallLogPop(642);
8922  return GraphicOutput;
8923 }
8924 
8925 // ---------------------------------------------------------------------------
8926 
8928 {
8929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
8930  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
8931  {
8932  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
8933  }
8934  Utilities->CallLogPop(643);
8935  return TrackVector.at(At);
8936 }
8937 
8938 // ---------------------------------------------------------------------------
8939 
8941 {
8942  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
8943  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
8944  {
8945  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
8946  " in InactiveTrackElementAt");
8947  }
8948  Utilities->CallLogPop(644);
8949  return InactiveTrackVector.at(At);
8950 }
8951 
8952 // ---------------------------------------------------------------------------
8953 
8954 bool TTrack::BlankElementAt(int Caller, int At) const
8955 {
8956  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
8957  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
8958  {
8959  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
8960  }
8961  if(TrackVector.at(At).SpeedTag == 0)
8962  {
8963  Utilities->CallLogPop(645);
8964  return true;
8965  }
8966  else
8967  {
8968  Utilities->CallLogPop(646);
8969  return false;
8970  }
8971 }
8972 
8973 // ---------------------------------------------------------------------------
8974 
8975 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
8976 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
8977  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
8978  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
8979  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
8980  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
8981 */
8982 {
8983  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
8984  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
8985  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
8986  TLocationNameMultiMapIterator SNIterator;
8987  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8988 
8989  if(SNRange.first == SNRange.second)
8990  {
8991  Utilities->CallLogPop(972);
8992  return false; // should have been caught earlier but include for completeness
8993  }
8994  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8995  {
8996  if(SNIterator->second < 0)
8997  continue; // exclude footcrossings
8998  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
8999  if(InactiveElement.TrackType == Concourse)
9000  continue; // only interested in locations where ActiveTrackElementName may be set
9001  THVPair HVPair;
9002  HVPair.first = InactiveElement.HLoc;
9003  HVPair.second = InactiveElement.VLoc;
9004  if(TrackMap.find(HVPair) == TrackMap.end())
9005  {
9006  throw Exception
9007  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
9008  }
9009  int TVPos = TrackMap.find(HVPair)->second;
9010  FirstNamedElement = TrackElementAt(560, TVPos);
9011  // first check linked on both sides, skip the check if not
9012  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9013  {
9014  continue;
9015  }
9016  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9017  // ActiveTrackElementNames are points and excluding trailing connections for points
9018  FirstNamedExitPos = 0;
9019  {
9020  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
9021  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9022  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9023  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9024  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9025  {
9026  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9027  {
9028  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
9029  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9030  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9031  // success, now check FirstNamedElement link not trailing points & if so all OK
9032  {
9033  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9034  {
9035  Utilities->CallLogPop(1002);
9036  return true;
9037  }
9038  }
9039  }
9040  }
9041  }
9042  // failed, try link 1
9043  FirstNamedExitPos = 1;
9044  {
9045  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
9046  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9047  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9048  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9049  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9050  {
9051  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9052  {
9053  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
9054  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9055  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9056  // success, now check FirstNamedElement link not trailing points & if so all OK
9057  {
9058  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9059  {
9060  Utilities->CallLogPop(1003);
9061  return true;
9062  }
9063  }
9064  }
9065  }
9066  }}
9067  Utilities->CallLogPop(1004);
9068  return false;
9069 }
9070 
9071 // ---------------------------------------------------------------------------
9072 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
9073  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
9074  // for success need two linked named location elements, so that one element of each train can be at the location
9075  // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
9076  // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
9077  // the two trains will occupy these 4 elements
9078  // All are track vector positions, all but the input being references and set within the function.
9079 {
9080 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
9081  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
9082  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
9083  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
9084  splitting.
9085 */
9086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
9087  AnsiString(FirstNamedElementPos));
9088  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9089  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9090 
9091  SecondNamedElementPos = -1;
9092  FirstNamedLinkedElementPos = -1;
9093  SecondNamedLinkedElementPos = -1;
9094  TLocationNameMultiMapIterator SNIterator;
9095  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9096 
9097  if(SNRange.first == SNRange.second) // i.e. location name not in map
9098  {
9099  Utilities->CallLogPop(1005);
9100  return false; // should have been caught earlier but include for completeness
9101  }
9102  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9103  {
9104  if(SNIterator->second < 0)
9105  continue; // exclude footcrossings
9106  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
9107  if(InactiveElement.TrackType == Concourse)
9108  continue; // only interested in locations where ActiveTrackElementName may be set
9109  THVPair HVPair;
9110  HVPair.first = InactiveElement.HLoc;
9111  HVPair.second = InactiveElement.VLoc;
9112  if(TrackMap.find(HVPair) == TrackMap.end())
9113  {
9114  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
9115  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
9116  // then it won't be found in TrackMap but it's still legitimate.
9117  {
9118  continue;
9119  }
9120  else // for anything else throw the error
9121  {
9122  throw Exception
9123  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
9124  );
9125  }
9126  }
9127  int TVPos = TrackMap.find(HVPair)->second;
9128  if(TVPos != FirstNamedElementPos)
9129  continue; // looking for an exact match
9130  FirstNamedElement = TrackElementAt(567, TVPos);
9131  // first check linked on both sides, skip the check if not
9132  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9133  {
9134  continue;
9135  }
9136  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9137  // ActiveTrackElementNames are points and excluding trailing connections for points
9138  FirstNamedExitPos = 0;
9139  {
9140  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
9141  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9142  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9143  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9144  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9145  {
9146  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9147  {
9148  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
9149  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9150  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9151  // success, now check FirstNamedElement link not trailing points & if so all OK
9152  {
9153  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9154  {
9155  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9156  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9157  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9158  Utilities->CallLogPop(1006);
9159  return true;
9160  }
9161  }
9162  }
9163  }
9164  }
9165  // failed, try link 1
9166  FirstNamedExitPos = 1;
9167  {
9168  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
9169  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9170  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9171  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9172  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9173  {
9174  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9175  {
9176  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
9177  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9178  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9179  // success, now check FirstNamedElement link not trailing points & if so all OK
9180  {
9181  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9182  {
9183  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9184  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9185  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9186  Utilities->CallLogPop(1007);
9187  return true;
9188  }
9189  }
9190  }
9191  }
9192  }}
9193  Utilities->CallLogPop(1008);
9194  return false;
9195 }
9196 
9197 // ---------------------------------------------------------------------------
9198 
9199 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
9200 {
9201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
9202  TLocationNameMultiMapIterator SNIterator;
9203  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9204 
9205  if(SNRange.first != SNRange.second)
9206  {
9207  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9208  {
9209  if(SNIterator->second < 0)
9210  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
9211  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
9212  SNIterator->second).TrackType == NamedNonStationLocation))
9213  {
9214  Utilities->CallLogPop(1121);
9215  return true;
9216  }
9217  }
9218  }
9219  Utilities->CallLogPop(848);
9220  return false;
9221 }
9222 
9223 // ---------------------------------------------------------------------------
9224 
9225 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
9226 {
9227 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
9228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
9229  "," + AnsiString(SpeedTag));
9230  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
9231  {
9232  Utilities->CallLogPop(949);
9233  return false;
9234  }
9235  bool FoundFlag;
9236  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
9237 
9238  if(!FoundFlag)
9239  {
9240  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
9241  }
9242  TTrackElement IAElement;
9243 
9244  if(SpeedTag == 68) // top sig
9245  {
9246  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
9247  {
9248  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
9249  IAElement = InactiveTrackElementAt(50, IMPair.first);
9250  else
9251  IAElement = InactiveTrackElementAt(51, IMPair.second);
9252  if(IAElement.LocationName == "")
9253  {
9254 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
9255  SignalPlatformGraphic = RailGraphics->gl76Striped;
9256  }
9257  else
9258  {
9259 // SignalPlatformGraphic = RailGraphics->Plat68;
9260  SignalPlatformGraphic = RailGraphics->gl76;
9261  }
9262  Utilities->CallLogPop(950);
9263  return true;
9264  }
9265  }
9266  else if(SpeedTag == 69) // bot sig
9267  {
9268  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
9269  {
9270  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
9271  IAElement = InactiveTrackElementAt(77, IMPair.first);
9272  else
9273  IAElement = InactiveTrackElementAt(78, IMPair.second);
9274  if(IAElement.LocationName == "")
9275  {
9276 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
9277  SignalPlatformGraphic = RailGraphics->bm77Striped;
9278  }
9279  else
9280  {
9281 // SignalPlatformGraphic = RailGraphics->Plat69;
9282  SignalPlatformGraphic = RailGraphics->bm77;
9283  }
9284  Utilities->CallLogPop(951);
9285  return true;
9286  }
9287  }
9288  else if(SpeedTag == 70) // left sig
9289  {
9290  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
9291  {
9292  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
9293  IAElement = InactiveTrackElementAt(55, IMPair.first);
9294  else
9295  IAElement = InactiveTrackElementAt(82, IMPair.second);
9296  if(IAElement.LocationName == "")
9297  {
9298 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
9299  SignalPlatformGraphic = RailGraphics->bm78Striped;
9300  }
9301  else
9302  {
9303 // SignalPlatformGraphic = RailGraphics->Plat70;
9304  SignalPlatformGraphic = RailGraphics->bm78;
9305  }
9306  Utilities->CallLogPop(952);
9307  return true;
9308  }
9309  }
9310  else if(SpeedTag == 71) // right sig
9311  {
9312  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
9313  {
9314  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
9315  IAElement = InactiveTrackElementAt(85, IMPair.first);
9316  else
9317  IAElement = InactiveTrackElementAt(86, IMPair.second);
9318  if(IAElement.LocationName == "")
9319  {
9320 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
9321  SignalPlatformGraphic = RailGraphics->gl79Striped;
9322  }
9323  else
9324  {
9325 // SignalPlatformGraphic = RailGraphics->Plat71;
9326  SignalPlatformGraphic = RailGraphics->gl79;
9327  }
9328  Utilities->CallLogPop(953);
9329  return true;
9330  }
9331  }
9332  Utilities->CallLogPop(954);
9333  return false;
9334 }
9335 
9336 // ---------------------------------------------------------------------------
9337 
9338 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
9339  // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
9340  // false if not, if NextPos == -1, or if only own train on the track
9341 {
9342  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
9343  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
9344  if(NextEntryPos < 0)
9345  {
9346  Utilities->CallLogPop(1348);
9347  return false;
9348  }
9349  TTrackElement TrackElement = TrackElementAt(713, NextPos);
9350 
9351  if(TrackElement.TrackType != Bridge)
9352  {
9353  Utilities->CallLogPop(1349);
9354  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
9355  }
9356 // bridge if reach here
9357  if(NextEntryPos > 1)
9358  {
9359  Utilities->CallLogPop(1350);
9360  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
9361  }
9362  else
9363  {
9364  Utilities->CallLogPop(1351);
9365  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
9366  }
9367 }
9368 
9369 // ---------------------------------------------------------------------------
9370 
9372 {
9373  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
9374  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
9375  {
9376  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
9377  }
9378  Utilities->CallLogPop(1483);
9379  return SelectVector.at(At);
9380 }
9381 
9382 // ---------------------------------------------------------------------------
9383 
9384 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
9385  // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
9386 {
9387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
9388  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
9389  bool FoundFlag = false;
9390  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
9391  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
9392 
9393  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
9394  Utilities->CallLogPop(1538);
9395  return FoundFlag;
9396 }
9397 
9398 // ---------------------------------------------------------------------------
9399 
9400 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
9401 {
9402 // return true if find an inactive element called 'Name'
9403  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
9404  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
9405  bool FoundFlag = false;
9406 
9407  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9408  {
9409  if(InactiveTrackVector.at(x).LocationName == Name)
9410  {
9411  FoundFlag = true;
9412  int V = InactiveTrackVector.at(x).VLoc;
9413  int H = InactiveTrackVector.at(x).HLoc;
9414  if(V > VLocHi)
9415  VLocHi = V;
9416  if(V < VLocLo)
9417  VLocLo = V;
9418  if(H < HLoc)
9419  HLoc = H;
9420  }
9421  }
9422  if(FoundFlag)
9423  {
9424  VPosHi = 16 * VLocHi;
9425  VPosLo = 16 * VLocLo;
9426  HPos = 16 * HLoc;
9427  Utilities->CallLogPop(1562);
9428  return true;
9429  }
9430  else
9431  {
9432  Utilities->CallLogPop(1563);
9433  return false;
9434  }
9435 }
9436 
9437 // ---------------------------------------------------------------------------
9438 
9439 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
9440 {
9441 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
9442 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
9443  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
9444  AnsiString(EndTVPosition));
9445  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
9446  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
9447 
9448 // get H & V values for the element adjacent to Link[0] & Link[1]
9449  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
9450  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
9451  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
9452  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
9453 
9454 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
9455  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
9456  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
9457  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
9458  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
9459 
9460  if(Link0Squares <= Link1Squares)
9461  {
9462  Utilities->CallLogPop(1851);
9463  return 0;
9464  }
9465  else
9466  {
9467  Utilities->CallLogPop(1852);
9468  return 1;
9469  }
9470 }
9471 
9472 // ---------------------------------------------------------------------------
9473 
9474 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
9475 { // element can be points or any other type
9476  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
9477  AnsiString(LinkPos));
9478  Derail = false;
9479  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
9480 
9481  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
9482  {
9483  if(TE.Attribute == 0)
9484  {
9485  Utilities->CallLogPop(663);
9486  return 1; // Att == 0 & ExitPos == 1 represent straight
9487  }
9488  else
9489  {
9490  Utilities->CallLogPop(664);
9491  return 3; // Att == 1 & ExitPos == 3 represent diverging
9492  }
9493  }
9494  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
9495  {
9496  if((LinkPos == 1) && (TE.Attribute == 0))
9497  {
9498  Utilities->CallLogPop(665);
9499  return 0; // Att == 0 represents straight
9500  }
9501  else if(LinkPos == 1)
9502  {
9503  Derail = true;
9504  Utilities->CallLogPop(666);
9505  return 0;
9506  }
9507  else if((LinkPos == 3) && (TE.Attribute == 1))
9508  {
9509  Utilities->CallLogPop(667);
9510  return 0;
9511  }
9512  else if(LinkPos == 3)
9513  {
9514  Derail = true;
9515  Utilities->CallLogPop(668);
9516  return 0;
9517  }
9518  }
9519  else if(LinkPos == 0)
9520  {
9521  Utilities->CallLogPop(669);
9522  return 1;
9523  }
9524  else if(LinkPos == 1)
9525  {
9526  Utilities->CallLogPop(670);
9527  return 0;
9528  }
9529  else if(LinkPos == 2)
9530  {
9531  Utilities->CallLogPop(671);
9532  return 3;
9533  }
9534  else if(LinkPos == 3)
9535  {
9536  Utilities->CallLogPop(672);
9537  return 2;
9538  }
9539  throw Exception("Error, failure in GetExitPos"); // should never reach here
9540 }
9541 
9542 // ----------------------------------------------------------------------------
9543 
9545 {
9546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
9547  LCVector.clear();
9548  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9549  {
9550  if(InactiveTrackVector.at(x).TrackType == LevelCrossing)
9551  {
9552  LCVector.push_back(x);
9553  }
9554  }
9555  Utilities->CallLogPop(1931);
9556  return;
9557 }
9558 
9559 // ---------------------------------------------------------------------------
9560 
9561 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
9562 /*
9563  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
9564  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
9565  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
9566  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
9567 */
9568 {
9569  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9570  AnsiString(Link));
9571  bool FoundFlag;
9572 
9573  TrainID = -1;
9574  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
9575 
9576  if(!FoundFlag)
9577  {
9578  Utilities->CallLogPop(2001);
9579  return false;
9580  }
9581  TTrackElement TE = TrackElementAt(882, VecPos);
9582 
9583  TrainID = TE.TrainIDOnElement;
9584  if(TE.TrackType == Bridge)
9585  {
9586  if(TE.TrainIDOnElement > -1)
9587  {
9588  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
9589  {
9590  TrainID = TE.TrainIDOnBridgeTrackPos01;
9591  }
9592  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
9593  {
9594  TrainID = TE.TrainIDOnBridgeTrackPos23;
9595  }
9596  else
9597  TrainID = -1; // shouldn't ever reach here but be safe
9598  }
9599  }
9600  if(TrainID == -1)
9601  {
9602  Utilities->CallLogPop(2002);
9603  return false;
9604  }
9605 // now get the train
9606  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
9607 
9608  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
9609  {
9610  Utilities->CallLogPop(2003);
9611  return true;
9612  }
9613  TrainID = -1;
9614  Utilities->CallLogPop(2004);
9615  return false;
9616 }
9617 
9618 // ---------------------------------------------------------------------------
9619 
9620 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
9621 /* New at v1.2.0
9622  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
9623  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
9624  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
9625  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
9626  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
9627  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
9628  Each of these is examined in turn for each route element in the relevant position.
9629 */
9630 {
9631  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
9632  "," + AnsiString(DiagonalLinkNumber));
9633  TrainID = -1;
9634  TPrefDirElement TempPrefDirElement;
9635  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
9636 
9637  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
9638  {
9639  Utilities->CallLogPop(2027);
9640  return true;
9641  }
9642 
9643  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
9644  {
9645  Utilities->CallLogPop(2028);
9646  return true;
9647  }
9648 
9649  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
9650  {
9651  Utilities->CallLogPop(2029);
9652  return true;
9653  }
9654 
9655  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
9656  {
9657  Utilities->CallLogPop(2030);
9658  return true;
9659  }
9660 
9661  Utilities->CallLogPop(2031);
9662  return false;
9663 }
9664 
9665 // ---------------------------------------------------------------------------
9666 
9667 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
9668 {
9669  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
9670  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
9671  TUserGraphicItem UGI;
9672  AnsiString JustFileName = "";
9673 
9674  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
9675  {
9676  UGI = UserGraphicVectorAt(17, x);
9677  int LastDelim = UGI.FileName.LastDelimiter('\\');
9678  if(LastDelim == 0) // can't find it so skip this item
9679  {
9680  continue;
9681  }
9682  else
9683  {
9684  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
9685  }
9686  Utilities->SaveFileString(VecFile, JustFileName);
9687  Utilities->SaveFileInt(VecFile, UGI.HPos);
9688  Utilities->SaveFileInt(VecFile, UGI.VPos);
9689  }
9690  Utilities->CallLogPop(2178);
9691 }
9692 
9693 // ---------------------------------------------------------------------------
9694 
9695 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
9696 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
9697 {
9698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
9699  int NumPlats = 0;
9700  TTrackElement TempElement;
9701  int TempInt;
9702 
9703  typedef std::list<int> TNamePosList;
9704  TNamePosList NamePosList;
9705  typedef TNamePosList::iterator TNPLIt;
9706  TNPLIt NPLIt;
9707  typedef std::list<int> TOnePlatList;
9708  TOnePlatList OnePlatList;
9709  typedef TOnePlatList::iterator TOPLIt;
9710  TOPLIt OPLIt;
9711 
9712  NamePosList.clear();
9713  OnePlatList.clear();
9714  for(unsigned int x = 0; x < TrackVector.size(); x++)
9715  {
9716  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
9717  {
9718  NamePosList.push_back(x);
9719  }
9720  }
9721  //NamePosList complete
9722 
9723  if(!NamePosList.empty()) //first value for the loop examination
9724  {
9725  OnePlatList.push_back(NamePosList.back());
9726  NamePosList.pop_back(); //erase from NPV as done with it here
9727  }
9728 
9729  while(!OnePlatList.empty()) //loop to examine all linked elements
9730  {
9731  TempInt = OnePlatList.front();
9732  TempElement = TrackElementAt(989, TempInt);
9733 
9734  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
9735  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
9736  {
9737  OnePlatList.push_back(TempElement.Conn[0]);
9738  NamePosList.erase(NPLIt);
9739  }
9740  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
9741  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
9742  {
9743  OnePlatList.push_back(TempElement.Conn[1]);
9744  NamePosList.erase(NPLIt);
9745  }
9746  //here when loaded any connecting links into OnePlatList, so can erase the front element
9747  OnePlatList.erase(OnePlatList.begin());
9748  if(OnePlatList.empty())
9749  {
9750  NumPlats++; //finished with current linked elements so can increment NumPlats
9751  if(!NamePosList.empty())
9752  {
9753  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
9754  NamePosList.pop_back(); //erase from NPV as done with it there
9755  }
9756  }
9757  }
9758  Utilities->CallLogPop(2218);
9759  return NumPlats;
9760 }
9761 
9762 // ---------------------------------------------------------------------------
9763 // UserGraphic, PrefDir & Route functions
9764 // ---------------------------------------------------------------------------
9765 
9767 {
9768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
9769  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
9770  {
9771  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
9772  }
9773  Utilities->CallLogPop(2194);
9774  return UserGraphicVector.at(At);
9775 }
9776 
9777 // ---------------------------------------------------------------------------
9778 
9779 int TOnePrefDir::LastElementNumber(int Caller) const
9780 {
9781  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
9782  int RetVal = PrefDirVector.size() - 1;
9783 
9784  if(RetVal < 0)
9785  {
9786  throw Exception("Return value negative in call to LastElementNumber");
9787  }
9788  Utilities->CallLogPop(114);
9789  return RetVal;
9790 }
9791 
9792 // ---------------------------------------------------------------------------
9794 {
9795  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
9796  if(PrefDirVector.empty())
9797  {
9798  throw Exception("PrefDirVector empty in call to LastElementPtr");
9799  }
9800  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
9801 
9802  Utilities->CallLogPop(115);
9803  return RetIT;
9804 }
9805 
9806 // ---------------------------------------------------------------------------
9808 {
9809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
9810  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
9811  {
9812  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
9813  }
9814  Utilities->CallLogPop(116);
9815  return PrefDirVector.at(At);
9816 }
9817 
9818 // ---------------------------------------------------------------------------
9820 {
9821  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
9822  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
9823  {
9824  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
9825  " in GetModifiablePrefDirElementAt");
9826  }
9827  Utilities->CallLogPop(117);
9828  return PrefDirVector.at(At);
9829 }
9830 
9831 // ---------------------------------------------------------------------------
9833 {
9834  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
9835  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
9836  {
9837  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
9838  }
9839  Utilities->CallLogPop(118);
9840  return SearchVector.at(At);
9841 }
9842 
9843 // ---------------------------------------------------------------------------
9845 {
9846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
9847  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
9848  {
9849  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
9850  }
9851  Utilities->CallLogPop(119);
9852  return SearchVector.at(At);
9853 }
9854 
9855 // ---------------------------------------------------------------------------
9856 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
9857 /*
9858  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
9859  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
9860  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
9861  set in later functions.
9862 */
9863 {
9864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
9865  ClearPrefDir();
9866  int TrackVectorPosition;
9867  TTrackElement TrackElement;
9868 
9869  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
9870  {
9871  Utilities->CallLogPop(126);
9872  return false;
9873  }
9874 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
9875  if(TrackElement.TrackType == Points)
9876  {
9877  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
9878  //it isn't known which trailing edge is the required PrefDir - could use the straight as
9879  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
9880  //best to prevent it to avoid problems
9881  Utilities->CallLogPop(127);
9882  return false;
9883  }
9884 */
9885  TPrefDirElement PrefDirElement(TrackElement);
9886 
9887  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
9888  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
9889  StorePrefDirElement(1, PrefDirElement); // enter first element
9890 // Note that ELink not set even if a buffer or continuation - these set in
9891 // ConvertPrefDirSearchVector after 2nd element added
9892 
9893  Utilities->CallLogPop(128);
9894  return true;
9895 }
9896 
9897 // ---------------------------------------------------------------------------
9898 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
9899 
9900 /*
9901  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
9902  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
9903  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
9904  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
9905  so that the calling function knows that the PrefDir is complete.
9906  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
9907  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
9908  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
9909  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
9910  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
9911  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
9912  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
9913  find the required element return false. CheckCount is used to keep track of set values to allow check later.
9914 */
9915 
9916 {
9917  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
9918  FinishElement = false;
9919  int TrackVectorPosition;
9920 
9921  TotalSearchCount = 0;
9922  TTrackElement TrackElement, TempTrackElement;
9923 
9924  if(PrefDirVector.size() == 0)
9925  {
9926  Utilities->CallLogPop(129);
9927  return false;
9928  }
9929  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
9930  {
9931  Utilities->CallLogPop(130);
9932  return false;
9933  }
9934 
9935 // set the search limits using the last stored element in PrefDirVector as the start point
9936 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
9937 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
9938 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
9939 
9940  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
9941 
9942  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
9943  {
9944  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
9945  SearchLimitHighH = TrackElement.HLoc + 15;
9946  }
9947  else
9948  {
9949  SearchLimitLowH = TrackElement.HLoc - 15;
9950  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
9951  }
9952 
9953  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
9954  {
9955  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
9956  SearchLimitHighV = TrackElement.VLoc + 15;
9957  }
9958  else
9959  {
9960  SearchLimitLowV = TrackElement.VLoc - 15;
9961  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
9962  }
9963 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
9964  check & TotalSearchCounts check
9965  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
9966  {
9967  ShowMessage("Unable to reach the selected element - too far ahead");
9968  Utilities->CallLogPop(1692);
9969  return false;
9970  }
9971 */
9972 // get last PrefDir element
9973  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
9974  {
9975  // check if TrackElement adjacent to any of the 4 XLinkPos'
9976  for(int x = 0; x < 4; x++)
9977  {
9978  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
9979  {
9980  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
9981  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
9982  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
9983  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
9984  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
9985  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
9986  // shouldn't ever get it in a serious railway though.
9987 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
9988  }
9989  }
9990  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
9991  {
9992  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
9993  SearchVector.clear(); // use this & convert to set all PrefDir element values
9994  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
9995  {
9997  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
9998  {
9999  FinishElement = true;
10000  }
10001  Utilities->CallLogPop(131);
10002  return true;
10003  }
10004  } // not an adjacent element
10005 
10006  // now check each of the 4 possible XLinkPos values
10007  for(int x = 0; x < 4; x++)
10008  {
10009  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
10010  {
10011  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
10012  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
10013  SearchVector.clear();
10014  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
10015  {
10017  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10018  {
10019  FinishElement = true;
10020  }
10021  Utilities->CallLogPop(132);
10022  return true;
10023  }
10024  }
10025  } // here if checked all possible exits without success
10026  ShowMessage(
10027  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10028  Utilities->CallLogPop(133);
10029  return false;
10030  }
10031 // dealt above with LastPrefDirElement being the start element (which can be points)
10032 
10033  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
10034  .ELinkPos] == Lead)) // leading point
10035  {
10036  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
10037  {
10038  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
10039  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
10040  // can't be buffers or gap if points
10041  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
10042  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
10043  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
10044  SearchVector.clear();
10045  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
10046  {
10048  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10049  {
10050  FinishElement = true;
10051  }
10052  Utilities->CallLogPop(134);
10053  return true;
10054  }
10055  }
10056  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
10057  {
10058  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
10059  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
10060  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
10061  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
10062  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
10063  SearchVector.clear();
10064  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
10065  {
10067  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10068  {
10069  FinishElement = true;
10070  }
10071  Utilities->CallLogPop(135);
10072  return true;
10073  }
10074  }
10075 // above dealt with immediate finds for leading point,
10076 // now deal with ordinary searches for leading point
10077  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
10078  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
10079  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
10080  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
10081  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
10082  SearchVector.clear();
10083  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
10084  {
10086  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10087  {
10088  FinishElement = true;
10089  }
10090  Utilities->CallLogPop(136);
10091  return true;
10092  }
10093  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
10094  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
10095  // note that CheckCount already increased to allow for XLinkPos & XLink
10096  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
10097  SearchVector.clear();
10098  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
10099  {
10101  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10102  {
10103  FinishElement = true;
10104  }
10105  Utilities->CallLogPop(137);
10106  return true;
10107  }
10108 // here if failed to find match for leading point
10109  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
10110  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
10111  ShowMessage(
10112  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10113  Utilities->CallLogPop(138);
10114  return false;
10115  }
10116 // leading point fully dealt with above
10117 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
10118 // separately as covered in ordinary search.
10119 
10120  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
10121  SearchVector.clear();
10122 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
10123  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
10124  {
10126  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10127  {
10128  FinishElement = true;
10129  }
10130  Utilities->CallLogPop(139);
10131  return true;
10132  }
10133  ShowMessage(
10134  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10135  Utilities->CallLogPop(140);
10136  return false; // failed to find required element
10137 }
10138 
10139 // ---------------------------------------------------------------------------
10140 
10141 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
10142 /*
10143  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
10144  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
10145  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
10146  Keep a count of entries in SearchVector during the current function call, so that this number can be
10147  erased for an unproductive branch search.
10148  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
10149  element. If so save it & return true. If not check if buffer, continuation, or earlier position
10150  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
10151  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
10152  If not any of above, store element in searchvector, set the new current element values from the
10153  SearchElement, then go back to the while loop for the next step in the search.
10154 */
10155 {
10156  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
10157  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
10158  int VectorCount = 0;
10159 
10160  while(true)
10161  {
10162  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
10163  {
10164  for(int x = 0; x < VectorCount; x++)
10165  SearchVector.erase(SearchVector.end() - 1);
10166  Utilities->CallLogPop(141);
10167  return false;
10168  }
10169  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
10170  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
10171  TPrefDirElement SearchElement(NextTrackElement);
10172  SearchElement.TrackVectorPosition = NextPosition;
10173  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
10174  SearchElement.ELinkPos = NextELinkPos;
10175  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
10176  int NextXLinkPos;
10177  if(SearchElement.ELinkPos == 0)
10178  NextXLinkPos = 1;
10179  if(SearchElement.ELinkPos == 1)
10180  NextXLinkPos = 0;
10181  if(SearchElement.ELinkPos == 2)
10182  NextXLinkPos = 3;
10183  if(SearchElement.ELinkPos == 3)
10184  NextXLinkPos = 2;
10185  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
10186  {
10187  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
10188  // but may be buffers, continuation or gap
10189  SearchElement.XLinkPos = NextXLinkPos;
10190  }
10191 // can't set XLink or XLinkPos yet if the element is a leading point.
10192 // check if found it
10193  if(SearchElement.TrackVectorPosition == RequiredPosition)
10194  {
10195  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
10196  VectorCount++; // not really needed but include for tidyness
10197  TotalSearchCount++;
10198  Utilities->CallLogPop(142);
10199  return true;
10200  }
10201 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
10202 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
10203 // at a time - drop this
10204 /*
10205  if(PrefDirVector.size() > 200)
10206  {
10207  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
10208  Utilities->CallLogPop(1419);
10209  return false;
10210  }
10211 */
10212 // check if a buffer or continuation
10213  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
10214  {
10215  for(int x = 0; x < VectorCount; x++)
10216  SearchVector.erase(SearchVector.end() - 1);
10217  Utilities->CallLogPop(143);
10218  return false;
10219  }
10220 // check if reached an earlier position on search PrefDir with same entry value
10221  for(unsigned int x = 0; x < SearchVector.size(); x++)
10222  {
10223  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
10224  {
10225  for(int x = 0; x < VectorCount; x++)
10226  SearchVector.erase(SearchVector.end() - 1);
10227  Utilities->CallLogPop(144);
10228  return false;
10229  }
10230  }
10231 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
10232 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
10233  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10234  {
10235  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
10236  {
10237  for(int x = 0; x < VectorCount; x++)
10238  SearchVector.erase(SearchVector.end() - 1);
10239  Utilities->CallLogPop(1417);
10240  return false;
10241  }
10242  }
10243 
10244 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
10245 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
10246 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
10248  {
10249  for(int x = 0; x < VectorCount; x++)
10250  SearchVector.erase(SearchVector.end() - 1);
10251  Utilities->CallLogPop(1691);
10252  return false;
10253  }
10254 
10255 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
10256  if(SearchVector.size() > 150)
10257  {
10258  for(int x = 0; x < VectorCount; x++)
10259  SearchVector.erase(SearchVector.end() - 1);
10260  Utilities->CallLogPop(1418);
10261  return false;
10262  }
10263 // check if reached a leading point
10264  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
10265  {
10266 // push element with XLink set to position [1]
10267  SearchElement.XLink = SearchElement.Link[1];
10268  SearchElement.XLinkPos = 1;
10269  SearchVector.push_back(SearchElement);
10270  VectorCount++;
10271  TotalSearchCount++;
10272  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
10273  // Note that have to use a TTrackElement in the recursive search, so SearchElement
10274  // can't be used. NextTrackElement is the corresponding TTrackElement.
10275  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
10276  {
10277  Utilities->CallLogPop(145);
10278  return true;
10279  }
10280  else
10281  {
10282 // remove leading point with XLinkPos [1]
10283  SearchVector.erase(SearchVector.end() - 1);
10284  VectorCount--;
10285 // push element with XLink set to position [3]
10286  SearchElement.XLink = SearchElement.Link[3];
10287  SearchElement.XLinkPos = 3;
10288  SearchVector.push_back(SearchElement);
10289  VectorCount++;
10290  TotalSearchCount++;
10291 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
10292  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
10293  {
10294  Utilities->CallLogPop(146);
10295  return true;
10296  }
10297  else
10298  {
10299  for(int x = 0; x < VectorCount; x++)
10300  SearchVector.erase(SearchVector.end() - 1);
10301  Utilities->CallLogPop(147);
10302  return false;
10303  }
10304  }
10305  } // if leading point
10306 // here if ordinary element, push it, inc vector & update CurrentTrackElement
10307 // ready for next element on PrefDir
10308  SearchVector.push_back(SearchElement);
10309  VectorCount++;
10310  TotalSearchCount++;
10311  XLinkPos = NextXLinkPos;
10312  CurrentTrackElement = SearchElement;
10313  } // while(true)
10314 }
10315 
10316 // ---------------------------------------------------------------------------
10317 
10319 /*
10320  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
10321  for each element on the search PrefDir, though if the last element is a leading point
10322  then the final XLink won't be set.
10323  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
10324  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
10325  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
10326 */
10327 {
10328  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
10329  if(SearchVector.size() == 0)
10330  {
10331  throw Exception("Error, SearchVector empty");
10332  }
10333 // get first SearchElement in order to set last PrefDirelement
10334  TPrefDirElement SearchElement = SearchVector.at(0);
10335 
10336 // set last PrefDir element XLink & ELink values if not already set
10337 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
10338  for(int x = 0; x < 4; x++)
10339  {
10340  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
10341  {
10342  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
10343  {
10344  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
10345  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
10346  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
10347  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
10348  }
10349  int ELinkPos;
10350  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
10351  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
10352  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
10353  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
10354  ELinkPos = 0;
10355  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
10356  ELinkPos = 3;
10357  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
10358  ELinkPos = 2;
10359  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
10360  {
10361  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
10362  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
10363  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
10364  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
10365  }
10366  break; // no point going any further
10367  }
10368  }
10369 // set EXNumber for last PrefDir element, unless already set
10370 // won't be set if was first element or a leading point
10371  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
10372  {
10373 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
10374  int EXArray[32][2] = {
10375  {4,6},{2,8}, //horizontal & vertical
10376  {2,4},{6,2},{8,6},{4,8}, //sharp curves
10377  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
10378  {1,9},{3,7} //forward & reverse diagonals
10379 */
10380 
10381  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
10382  {
10383  throw Exception("Error in EntryExitNumber 1");
10384  }
10385 
10386  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
10387  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
10388  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
10389  }
10390 // Last PrefDir element now complete
10391 
10392 // construct remaining PrefDir elements from searchvector
10393  for(unsigned int x = 0; x < SearchVector.size(); x++)
10394  {
10395  SearchElement = SearchVector.at(x);
10396  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
10397  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
10398  PrefDirElement.ELink = SearchElement.ELink;
10399  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
10400  PrefDirElement.XLink = SearchElement.XLink;
10401  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
10402 // if XLink & XLinkPos not set don't account for them in CheckCount
10403  if(PrefDirElement.XLink == -1)
10404  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10405  // & TrackVectorPosition
10406  else
10407  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10408  // XLink, XLinkPos, TrackVectorPosition
10409 
10410 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
10411  if(PrefDirElement.XLink != -1)
10412  {
10413  if(!(PrefDirElement.EntryExitNumber()))
10414  {
10415  throw Exception("Error in EntryExitNumber 2");
10416  }
10417  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
10418  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
10419  PrefDirElement.CheckCount++;
10420  // all values now incorporated if not a leading point
10421  }
10422 // store PrefDir element
10423  StorePrefDirElement(2, PrefDirElement);
10424  }
10425 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
10426  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
10427  {
10428  if(ValidatePrefDir(2))
10429  {;
10430  } // error messages given within function
10431  }
10433 /* drop this, check dropped from search
10434  if(PrefDirVector.size() > 200)
10435  {
10436  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
10437  }
10438 */
10439  Utilities->CallLogPop(148);
10440 }
10441 
10442 // ---------------------------------------------------------------------------
10443 
10444 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
10445 /*
10446  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
10447  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
10448 */
10449 {
10450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
10451  LeadingPoints = false;
10452  if(PrefDirVector.empty())
10453  {
10454  Utilities->CallLogPop(1786);
10455  return false; // should never be empty but allow for it for safety
10456  }
10457  if(PrefDirVector.size() == 1)
10458  {
10459  Utilities->CallLogPop(149);
10460  return false; // can't end if only one element
10461  }
10462 /*
10463  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
10464  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
10465  {
10466  Utilities->CallLogPop(150);
10467  return true;
10468  }
10469 */
10470 // allow for anything but leading points
10471  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
10472  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
10473  {
10474  Utilities->CallLogPop(1776);
10475  return true;
10476  }
10477  else
10478  {
10479  LeadingPoints = true;
10480  Utilities->CallLogPop(151);
10481  return false;
10482  }
10483 }
10484 
10485 // ---------------------------------------------------------------------------
10486 
10488 /*
10489  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
10490  and that every element is connected to the next element
10491 */
10492 {
10493  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
10494  int Position;
10495  AnsiString ErrorString;
10496  bool Error = false;
10497 
10498  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10499  {
10500  if(PrefDirVector.at(x).HLoc == -2000000000)
10501  {
10502  Error = true;
10503  ErrorString = "HLoc";
10504  Position = x;
10505  }
10506  if(PrefDirVector.at(x).VLoc == -2000000000)
10507  {
10508  Error = true;
10509  ErrorString = "VLoc";
10510  Position = x;
10511  }
10512  if(PrefDirVector.at(x).ELink == -1)
10513  {
10514  Error = true;
10515  ErrorString = "ELink";
10516  Position = x;
10517  }
10518  if(PrefDirVector.at(x).ELinkPos == -1)
10519  {
10520  Error = true;
10521  ErrorString = "ELinkPos";
10522  Position = x;
10523  }
10524  if(PrefDirVector.at(x).XLink == -1)
10525  {
10526  Error = true;
10527  ErrorString = "XLink";
10528  Position = x;
10529  }
10530  if(PrefDirVector.at(x).XLinkPos == -1)
10531  {
10532  Error = true;
10533  ErrorString = "XLinkPos";
10534  Position = x;
10535  }
10536  if(PrefDirVector.at(x).SpeedTag == 0)
10537  {
10538  Error = true;
10539  ErrorString = "Tag";
10540  Position = x;
10541  }
10542  if(PrefDirVector.at(x).TrackVectorPosition == -1)
10543  {
10544  Error = true;
10545  ErrorString = "TrackVectorPosition";
10546  Position = x;
10547  }
10548  if(PrefDirVector.at(x).EXNumber == -1)
10549  {
10550  Error = true;
10551  ErrorString = "EXNumber";
10552  Position = x;
10553  }
10554  if(PrefDirVector.at(x).CheckCount != 9)
10555  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
10556  {
10557  Error = true;
10558  ErrorString = "CheckCount";
10559  Position = x;
10560  }
10561 // extra checks
10562  if(PrefDirVector.at(x).EXGraphicPtr == 0)
10563  {
10564  Error = true;
10565  ErrorString = "EntryGraphicPtr";
10566  Position = x;
10567  }
10568  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
10569  {
10570  Error = true;
10571  ErrorString = "EntryDirectionGraphicPtr";
10572  Position = x;
10573  }
10574 // end of extra checks
10575  if(x > 0)
10576  {
10577  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
10578  {
10579  Error = true;
10580  ErrorString = "Last XLink not connected to this element";
10581  Position = x;
10582  }
10583  }
10584  }
10585  if(Error)
10586  {
10587  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
10588  }
10589  else
10590  {
10591  Utilities->CallLogPop(153);
10592  return true;
10593  }
10594 }
10595 
10596 // ---------------------------------------------------------------------------
10597 
10598 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
10599 /*
10600  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
10601  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
10602  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
10603  or a leading point.
10604 */
10605 {
10606  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10607  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
10608  {
10609  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
10610  {
10611  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
10612  {
10613  ErasePrefDirElementAt(1, PrefDirVecPos);
10614  }
10615  if(PrefDirVector.size() == 0)
10616  {
10617  Utilities->CallLogPop(154);
10618  return true;
10619  }
10620  if(PrefDirVector.size() == 1)
10621  {
10622  PrefDirVector.at(x - 1).ELinkPos = -1;
10623  PrefDirVector.at(x - 1).ELink = -1;
10624  PrefDirVector.at(x - 1).XLinkPos = -1;
10625  PrefDirVector.at(x - 1).XLink = -1;
10626  PrefDirVector.at(x - 1).EXNumber = -1;
10627  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
10628  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
10629  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
10630  Utilities->CallLogPop(155);
10631  return true;
10632  }
10633  // here with truncate element not first element, so ELink & ELinkPos set
10634  // unset XLink & Pos if a leading point
10635  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
10636  {
10637  PrefDirVector.at(x - 1).XLinkPos = -1;
10638  PrefDirVector.at(x - 1).XLink = -1;
10639  PrefDirVector.at(x - 1).EXNumber = -1;
10640  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
10641  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
10642  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
10643  Utilities->CallLogPop(156);
10644  return true;
10645  }
10646  Utilities->CallLogPop(157);
10647  return true;
10648  }
10649  }
10650  Utilities->CallLogPop(158);
10651  return false;
10652 }
10653 
10654 // ---------------------------------------------------------------------------
10655 
10656 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
10657  const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
10658 /*
10659  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
10660  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
10661  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
10662  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
10663  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
10664  displayed.
10665 */
10666 {
10667  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
10668  AnsiString((short)BuildingPrefDir));
10669  int HPos, VPos;
10670 
10671  if(PrefDirSize() == 0)
10672  {
10673  Utilities->CallLogPop(159);
10674  return;
10675  }
10676  for(unsigned int x = 0; x < PrefDirSize(); x++)
10677  {
10678  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
10679 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
10680 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
10681 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
10682  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
10683  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
10684  // only the front half of which will be overplotted by the back of the train, then when the train is
10685  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
10686  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
10687  {
10688  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
10689  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
10690  {
10691  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
10692  }
10693  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
10694  // Route, no direction if a single element
10695  {
10696  if(x == 0)
10697  {
10698  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
10699  }
10700  if(x == (PrefDirSize() - 1))
10701  {
10702  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
10703  }
10704  }
10705  }
10706  }
10707 
10708 // set start & end element colours if building a PrefDir
10709  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
10710  {
10711  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
10712  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
10713  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
10714  // set last element colour
10715  if(PrefDirSize() > 1)
10716  {
10717  unsigned int LatestPos = PrefDirSize() - 1;
10718  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
10719  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
10720  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
10721  }
10722  }
10723  Disp->Update();
10724  Utilities->CallLogPop(160);
10725 }
10726 
10727 // ---------------------------------------------------------------------------
10728 
10730 /*
10731  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
10732  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
10733 */
10734 {
10735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
10736  if(PrefDirSize() == 0)
10737  {
10738  Utilities->CallLogPop(1547);
10739  return;
10740  }
10741 
10742  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10743  bool FoundFlag;
10745  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
10746 
10747  while(MMIT != PrefDir4MultiMap.end())
10748  {
10749  H = MMIT->first.first;
10750  V = MMIT->first.second;
10751  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10752  // always found in order, any missing have PrefDirPosx == -1
10753  if(PrefDirPos0 > -1)
10754  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
10755  if(PrefDirPos1 > -1)
10756  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
10757  if(PrefDirPos2 > -1)
10758  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
10759  if(PrefDirPos3 > -1)
10760  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
10761  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
10762  { // need to plot all 4 in order to obtain all the direction graphics
10763  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10764  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10765  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10766  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10767  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
10768  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
10769  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
10770  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
10771  MMIT++;
10772  MMIT++;
10773  MMIT++;
10774  MMIT++;
10775  }
10776  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
10777  {
10778  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
10779  { // 0 & 1 constitute the bidirectional PrefDir
10780  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
10781  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
10782  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10783  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10784  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10785  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10786  MMIT++;
10787  MMIT++;
10788  MMIT++;
10789  }
10790  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
10791  { // 0 & 2 constitute the bidirectional PrefDir
10792  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
10793  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
10794  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10795  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10796  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
10797  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
10798  MMIT++;
10799  MMIT++;
10800  MMIT++;
10801  }
10802  else
10803  { // 1 & 2 constitute the bidirectional PrefDir
10804  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
10805  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
10806  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10807  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10808  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
10809  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
10810  MMIT++;
10811  MMIT++;
10812  MMIT++;
10813  }
10814  }
10815  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
10816  {
10817  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
10818  { // 0 & 1 constitute the bidirectional PrefDir
10819  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10820  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10821  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10822  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10823  MMIT++;
10824  MMIT++;
10825  }
10826  else
10827  { // 2 unidirectional PrefDirs
10828  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
10829  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
10830  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
10831  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
10832  MMIT++;
10833  MMIT++;
10834  }
10835  }
10836  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
10837  {
10838  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
10839  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
10840  MMIT++;
10841  }
10842  }
10843  Disp->Update();
10844  Utilities->CallLogPop(1548);
10845 }
10846 
10847 // ---------------------------------------------------------------------------
10848 
10849 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
10850 {
10851  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
10852  int TempInt;
10853 
10854  ClearPrefDir();
10855  int NumberOfPrefDirElements = 0;
10856 
10857  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
10858  for(int x = 0; x < NumberOfPrefDirElements; x++)
10859  {
10860  VecFile >> TempInt; // TrackVectorPosition
10861  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
10862  LoadPrefDirElement.TrackVectorPosition = TempInt;
10863  VecFile >> TempInt;
10864  LoadPrefDirElement.ELink = TempInt;
10865  VecFile >> TempInt;
10866  LoadPrefDirElement.ELinkPos = TempInt;
10867  VecFile >> TempInt;
10868  LoadPrefDirElement.XLink = TempInt;
10869  VecFile >> TempInt;
10870  LoadPrefDirElement.XLinkPos = TempInt;
10871  VecFile >> TempInt;
10872  LoadPrefDirElement.EXNumber = TempInt;
10873  VecFile >> TempInt;
10874  LoadPrefDirElement.CheckCount = TempInt;
10875  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
10876  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
10877  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
10878  if(!(LoadPrefDirElement.IsARoute))
10879  {
10880  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
10881  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
10882  }
10883  else
10884  {
10885  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
10886  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
10887  LoadPrefDirElement.ConsecSignals);
10888  }
10889  StorePrefDirElement(5, LoadPrefDirElement);
10890  Utilities->LoadFileString(VecFile); // marker
10891  }
10893  Utilities->CallLogPop(161);
10894 }
10895 
10896 // ---------------------------------------------------------------------------
10897 
10898 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
10899 {
10900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
10901  int TempInt;
10902 
10903  ClearPrefDir();
10904  int NumberOfPrefDirElements = 0;
10905 
10906  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
10907  for(int x = 0; x < NumberOfPrefDirElements; x++)
10908  {
10909  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
10910  VecFile >> TempInt; // TrackVectorPosition
10911  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt));
10912  LoadPrefDirElement.TrackVectorPosition = TempInt;
10913  VecFile >> TempInt;
10914  LoadPrefDirElement.ELink = TempInt;
10915  VecFile >> TempInt;
10916  LoadPrefDirElement.ELinkPos = TempInt;
10917  VecFile >> TempInt;
10918  LoadPrefDirElement.XLink = TempInt;
10919  VecFile >> TempInt;
10920  LoadPrefDirElement.XLinkPos = TempInt;
10921  VecFile >> TempInt;
10922  LoadPrefDirElement.EXNumber = TempInt;
10923  VecFile >> TempInt;
10924  LoadPrefDirElement.CheckCount = TempInt;
10925  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
10926  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
10927  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
10928  if(!(LoadPrefDirElement.IsARoute))
10929  {
10930  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
10931  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
10932  }
10933  else
10934  {
10935  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
10936  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
10937  LoadPrefDirElement.ConsecSignals);
10938  }
10939  StorePrefDirElement(0, LoadPrefDirElement);
10940  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
10941  }
10943  Utilities->CallLogPop(1509);
10944 }
10945 
10946 // ---------------------------------------------------------------------------
10947 
10948 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
10949 /*
10950  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
10951  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
10952 */
10953 {
10954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
10955  int TempInt;
10956  int NumberOfPrefDirElements = 0;
10957 
10958  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
10959  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
10960  {
10961  Utilities->CallLogPop(1152);
10962  return false;
10963  }
10964  for(int x = 0; x < NumberOfPrefDirElements; x++)
10965  {
10966  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
10967  {
10968  Utilities->CallLogPop(1766);
10969  return false;
10970  }
10971  VecFile >> TempInt;
10972  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
10973  {
10974  Utilities->CallLogPop(163);
10975  return false;
10976  }
10977  VecFile >> TempInt;
10978  if((TempInt < -1) || (TempInt > 9)) // ELink
10979  {
10980  Utilities->CallLogPop(162);
10981  return false;
10982  }
10983  VecFile >> TempInt;
10984  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
10985  {
10986  Utilities->CallLogPop(164);
10987  return false;
10988  }
10989  VecFile >> TempInt;
10990  if((TempInt < -1) || (TempInt > 9)) // XLink
10991  {
10992  Utilities->CallLogPop(165);
10993  return false;
10994  }
10995  VecFile >> TempInt;
10996  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
10997  {
10998  Utilities->CallLogPop(166);
10999  return false;
11000  }
11001  VecFile >> TempInt;
11002  if((TempInt < -1) || (TempInt > 27)) // EXNumber
11003  {
11004  Utilities->CallLogPop(167);
11005  return false;
11006  }
11007  VecFile >> TempInt;
11008  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
11009  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
11010  // ELinkPos, XLink, XLinkPos & EXNumber
11011  {
11012  Utilities->CallLogPop(168);
11013  return false;
11014  }
11015  VecFile >> TempInt;
11016  if((TempInt != 0) && (TempInt != 1)) // RouteElement
11017  {
11018  Utilities->CallLogPop(1147);
11019  return false;
11020  }
11021  VecFile >> TempInt;
11022  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
11023  {
11024  Utilities->CallLogPop(1510);
11025  return false;
11026  }
11027  VecFile >> TempInt;
11028  if((TempInt != 0) && (TempInt != 1)) // ConsecSignals
11029  {
11030  Utilities->CallLogPop(1148);
11031  return false;
11032  }
11033  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
11034  {
11035  Utilities->CallLogPop(1700);
11036  return false;
11037  }
11038  }
11039  Utilities->CallLogPop(169);
11040  return true;
11041 }
11042 
11043 // ---------------------------------------------------------------------------
11044 
11045 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
11046 {
11047  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
11048  int NumberOfPrefDirElements = PrefDirVector.size();
11049 
11050  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
11051  for(int y = 0; y < NumberOfPrefDirElements; y++)
11052  {
11053  VecFile << y << '\n'; // extra
11054  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n';
11055  VecFile << PrefDirVector.at(y).ELink << '\n';
11056  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
11057  VecFile << PrefDirVector.at(y).XLink << '\n';
11058  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
11059  VecFile << PrefDirVector.at(y).EXNumber << '\n';
11060  VecFile << PrefDirVector.at(y).CheckCount << '\n';
11061  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
11062  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
11063  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).ConsecSignals);
11064  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
11065  {
11066  VecFile << "************" << '\0' << '\n'; // marker
11067  }
11068  else
11069  {
11070  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11071  }
11072  }
11073  Utilities->CallLogPop(170);
11074 }
11075 
11076 // ---------------------------------------------------------------------------
11077 
11078 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
11079 {
11080  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
11081  int NumberOfSearchElements = SearchVector.size();
11082 
11083  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
11084  for(int y = 0; y < NumberOfSearchElements; y++)
11085  {
11086  VecFile << y << '\n'; // extra
11087  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
11088  VecFile << SearchVector.at(y).ELink << '\n';
11089  VecFile << SearchVector.at(y).ELinkPos << '\n';
11090  VecFile << SearchVector.at(y).XLink << '\n';
11091  VecFile << SearchVector.at(y).XLinkPos << '\n';
11092  VecFile << SearchVector.at(y).EXNumber << '\n';
11093  VecFile << SearchVector.at(y).CheckCount << '\n';
11094  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
11095  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
11096  Utilities->SaveFileBool(VecFile, SearchVector.at(y).ConsecSignals);
11097  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
11098  {
11099  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11100  }
11101  else
11102  {
11103  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11104  }
11105  }
11106  Utilities->CallLogPop(1847);
11107 }
11108 
11109 // ---------------------------------------------------------------------------
11110 
11111 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
11112 /*
11113  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
11114  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
11115 */
11116 {
11117  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
11118  AnsiString(VLoc));
11119  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
11120 
11121  if(VecPos > -1)
11122  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
11123  else
11124  {
11125  Utilities->CallLogPop(171);
11126  return;
11127  }
11128  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
11129  if(VecPos > -1)
11130  ErasePrefDirElementAt(3, VecPos);
11131  else
11132  {
11133  Utilities->CallLogPop(172);
11134  return;
11135  }
11136  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
11137  if(VecPos > -1)
11138  ErasePrefDirElementAt(4, VecPos);
11139  else
11140  {
11141  Utilities->CallLogPop(173);
11142  return;
11143  }
11144  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
11145  if(VecPos > -1)
11146  ErasePrefDirElementAt(5, VecPos);
11147  else
11148  {
11149  Utilities->CallLogPop(174);
11150  return;
11151  }
11152  Utilities->CallLogPop(175);
11153 }
11154 
11155 // ---------------------------------------------------------------------------
11156 /*
11157  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
11158  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
11159 
11160  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
11161  in their place so that existing linkages will be preserved. At this stage this function is called to remove
11162  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
11163  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
11164  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
11165  PrefDirVector to correspond to the new track layout.
11166 
11167  {
11168  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
11169  if(PrefDirSize() == 0)
11170  {
11171  Utilities->CallLogPop(176);
11172  return;
11173  }
11174  for(int x=(PrefDirVector.size()-1);x>=0;x--)
11175  {
11176  int TV = PrefDirVector.at(x).TrackVectorPosition;
11177  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
11178  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
11179  if(Track->BlankElementAt(0, TV))
11180  {
11181  ErasePrefDirElementAt(6, x);
11182  }
11183  //if was a blankelement at x then ConnELink and ConnXLink both -1
11184  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
11185  {
11186  ErasePrefDirElementAt(7, x);
11187  }
11188  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
11189  //needs to be erased once, but if don't use 'else' then will erase two elements
11190  //since 'x' will correspond to the element after the first erased element
11191  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
11192  {
11193  ErasePrefDirElementAt(8, x);
11194  }
11195  }
11196  Utilities->CallLogPop(177);
11197  }
11198 */
11199 // ---------------------------------------------------------------------------
11200 
11201 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
11202 /*
11203  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
11204  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
11205 */
11206 {
11207  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
11208  bool AlreadyPresent, FoundFlag;
11209  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11210 
11211  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
11212  {
11213  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
11214  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11215  AlreadyPresent = false;
11216  if(FoundFlag)
11217  {
11218  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
11219  AlreadyPresent = true;
11220  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
11221  AlreadyPresent = true;
11222  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
11223  AlreadyPresent = true;
11224  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
11225  AlreadyPresent = true;
11226  }
11227  if(!AlreadyPresent)
11228  StorePrefDirElement(4, TempElement);
11229  }
11231  Utilities->CallLogPop(178);
11232 }
11233 /* earlier brute force search
11234  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
11235  {
11236  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
11237  bool AlreadyPresent = false;
11238  for(unsigned int y = 0;y<PrefDirSize();y++)
11239  {
11240  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
11241  }
11242  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
11243  }
11244 */
11245 
11246 // ---------------------------------------------------------------------------
11247 
11249 /*
11250  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
11251  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
11252  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
11253  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
11254  positions are likely to have changed, so this function is called to reset all the necessary connections and
11255  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
11256  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
11257  shouldn't have changed.
11258 */
11259 {
11260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
11261  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11262  {
11263  bool FoundFlag;
11264  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11265  if(FoundFlag)
11266  {
11267  PrefDirVector.at(x).TrackVectorPosition = VecPos;
11268  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
11269  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
11270  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
11271  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
11272  for(unsigned int z = 0; z < 4; z++)
11273  {
11274  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
11275  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
11276  }
11277  }
11278  else
11279  {
11280  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
11281  }
11282  }
11283  Utilities->CallLogPop(179);
11284 }
11285 
11286 // ---------------------------------------------------------------------------
11287 
11289 /*
11290  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
11291 */
11292 {
11293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
11294  bool DiscrepancyFound = false;
11295 
11296  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11297  {
11298  bool FoundFlag;
11299  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11300  if(FoundFlag)
11301  {
11302  TPrefDirElement PE = PrefDirVector.at(x);
11303  if(PE.TrackVectorPosition != VecPos)
11304  DiscrepancyFound = true;
11305  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11306  {
11307  DiscrepancyFound = true;
11308  break;
11309  }
11310  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11311  {
11312  DiscrepancyFound = true;
11313  break;
11314  }
11315  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
11316  {
11317  DiscrepancyFound = true;
11318  break;
11319  }
11320  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
11321  {
11322  DiscrepancyFound = true;
11323  break;
11324  }
11325  }
11326  else
11327  DiscrepancyFound = true;
11328  }
11329  if(DiscrepancyFound)
11330  {
11331  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
11332  ClearPrefDir(); // also clears multimap
11333  }
11334  Utilities->CallLogPop(1436);
11335 }
11336 
11337 // ---------------------------------------------------------------------------
11338 
11340 /*
11341  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
11342  return true for OK
11343 */
11344 {
11345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
11346  bool DiscrepancyFound = false;
11347 
11348  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11349  {
11350  bool FoundFlag;
11351  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11352  if(FoundFlag)
11353  {
11354  TPrefDirElement PE = PrefDirVector.at(x);
11355  if(PE.TrackVectorPosition != VecPos)
11356  DiscrepancyFound = true;
11357  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11358  {
11359  DiscrepancyFound = true;
11360  break;
11361  }
11362  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11363  {
11364  DiscrepancyFound = true;
11365  break;
11366  }
11367  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
11368  {
11369  DiscrepancyFound = true;
11370  break;
11371  }
11372  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
11373  {
11374  DiscrepancyFound = true;
11375  break;
11376  }
11377  }
11378  else
11379  DiscrepancyFound = true;
11380  }
11381  Utilities->CallLogPop(1512);
11382  return !DiscrepancyFound;
11383 }
11384 
11385 // ---------------------------------------------------------------------------
11386 
11387 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
11388 /*
11389  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
11390  turn and for the overall sizes.
11391 */
11392 {
11393  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
11394  bool FoundFlag = false;
11395  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
11396 
11397  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
11398  {
11399  TPrefDirElement CheckElement = PrefDirVector.at(a);
11400  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
11401  if(!FoundFlag)
11402  {
11403  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
11404  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
11405  }
11406  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
11407  {
11408  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
11409  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
11410  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
11411  }
11412  }
11413  if(PrefDirVector.size() != PrefDir4MultiMap.size())
11414  {
11415  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
11416  + " Caller=" + (AnsiString)Caller);
11417  }
11418  Utilities->CallLogPop(180);
11419 }
11420 
11421 // ---------------------------------------------------------------------------
11422 
11423 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
11424  int &PrefDirPos3)
11425 /*
11426  There are up to four elements at each H & V position in the PrefDirVector - two directions, and up to
11427  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
11428  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
11429  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
11430  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
11431 */
11432 {
11433  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
11434  AnsiString(VLoc));
11435  THVPair PrefDirMapKeyPair;
11436 
11437  PrefDirPos0 = -1;
11438  PrefDirPos1 = -1;
11439  PrefDirPos2 = -1;
11440  PrefDirPos3 = -1;
11441  FoundFlag = false;
11442  PrefDirMapKeyPair.first = HLoc;
11443  PrefDirMapKeyPair.second = VLoc;
11444  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
11445 
11446  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
11447  if(ItPair.first == ItPair.second)
11448  {
11449  Utilities->CallLogPop(181);
11450  return;
11451  }
11452  else
11453  {
11454  FoundFlag = true;
11455  PrefDirPos0 = ItPair.first->second;
11456  ItPair.first++;
11457  if(ItPair.first == ItPair.second)
11458  {
11459  Utilities->CallLogPop(182);
11460  return;
11461  }
11462  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11463  PrefDirPos1 = ItPair.first->second;
11464  ItPair.first++;
11465  if(ItPair.first == ItPair.second)
11466  {
11467  Utilities->CallLogPop(183);
11468  return;
11469  }
11470  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11471  PrefDirPos2 = ItPair.first->second;
11472  ItPair.first++;
11473  if(ItPair.first == ItPair.second)
11474  {
11475  Utilities->CallLogPop(184);
11476  return;
11477  }
11478  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11479  PrefDirPos3 = ItPair.first->second;
11480  }
11481  Utilities->CallLogPop(185);
11482 }
11483 
11484 // ---------------------------------------------------------------------------
11485 
11486 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
11487 /*
11488  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
11489 */
11490 {
11491  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
11492  PrefDirVector.push_back(LoadPrefDirElement);
11493  THVPair PrefDir4MultiMapKeyPair;
11494  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
11495 
11496  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
11497  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
11498  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
11499  PrefDir4MultiMapEntry.second = LastElementNumber(68);
11500  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
11501 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
11502  Utilities->CallLogPop(186);
11503 }
11504 
11505 // ---------------------------------------------------------------------------
11506 
11507 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
11508 /*
11509  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
11510  4MultiMap if they are greater than the erased value.
11511 */
11512 {
11513  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
11514  bool FoundFlag;
11515 
11516  if(!PrefDirVector.empty())
11517  {
11518  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
11519  if(!FoundFlag)
11520  {
11521  throw Exception("Failed to find PrefDir4MultiMap erase element");
11522  }
11523  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
11524  PrefDir4MultiMap.erase(EraseIt);
11525  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
11527  }
11528  Utilities->CallLogPop(187);
11529 }
11530 
11531 // ---------------------------------------------------------------------------
11532 
11533 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
11534 /*
11535  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
11536  4MultiMap if they are greater than the erased value.
11537 */
11538 {
11539  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
11540  AnsiString(ErasedElementNumber));
11541  if(!PrefDir4MultiMap.empty())
11542  {
11543  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
11544  {
11545  if(MapPtr->second > ErasedElementNumber)
11546  MapPtr->second--;
11547  }
11548  }
11549  Utilities->CallLogPop(1450);
11550 }
11551 
11552 // ---------------------------------------------------------------------------
11553 
11554 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
11555 /*
11556  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
11557  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
11558  nothing is found this is an error but the error message is given in the calling function.
11559 */
11560 {
11561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
11562  FoundFlag = false;
11563  if(PrefDirVectorPosition >= PrefDirVector.size())
11564  {
11565  throw Exception("PrefDirVectorPosition out of range");
11566  }
11567  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
11568  THVPair PrefDir4MultiMapKeyPair;
11569 
11570  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
11571  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
11572  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
11573 
11574  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
11575  if(ItPair.first == ItPair.second)
11576  {
11577  Utilities->CallLogPop(188);
11578  return ItPair.first; // nothing found but have to return an iterator, FoundFlag indicates nothing found
11579  }
11580  else
11581  {
11582  if(ItPair.first->second == PrefDirVectorPosition)
11583  {
11584  FoundFlag = true;
11585  Utilities->CallLogPop(189);
11586  return ItPair.first;
11587  }
11588  ItPair.first++;
11589  if(ItPair.first == ItPair.second)
11590  {
11591  Utilities->CallLogPop(190);
11592  return ItPair.first; // nothing found
11593  }
11594  if(ItPair.first->second == PrefDirVectorPosition)
11595  {
11596  FoundFlag = true;
11597  Utilities->CallLogPop(191);
11598  return ItPair.first;
11599  }
11600  ItPair.first++;
11601  if(ItPair.first == ItPair.second)
11602  {
11603  Utilities->CallLogPop(192);
11604  return ItPair.first; // nothing found
11605  }
11606  if(ItPair.first->second == PrefDirVectorPosition)
11607  {
11608  FoundFlag = true;
11609  Utilities->CallLogPop(193);
11610  return ItPair.first;
11611  }
11612  ItPair.first++;
11613  if(ItPair.first == ItPair.second)
11614  {
11615  Utilities->CallLogPop(194);
11616  return ItPair.first; // nothing found
11617  }
11618  if(ItPair.first->second == PrefDirVectorPosition)
11619  {
11620  FoundFlag = true;
11621  Utilities->CallLogPop(195);
11622  return ItPair.first;
11623  }
11624  }
11625  Utilities->CallLogPop(196);
11626  return ItPair.first; // nothing found
11627 }
11628 
11629 // ---------------------------------------------------------------------------
11630 
11631 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
11632 /*
11633  Although there may be up to four entries at one H & V position this function gets just one. It is
11634  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
11635  at H & V.
11636 */
11637 {
11638  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11639  THVPair PrefDir4MultiMapKeyPair;
11640 
11641  PrefDir4MultiMapKeyPair.first = HLoc;
11642  PrefDir4MultiMapKeyPair.second = VLoc;
11643  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
11644 
11645  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
11646  if(ItPair.first == ItPair.second) // nothing found
11647  {
11648  Utilities->CallLogPop(197);
11649  return -1;
11650  }
11651  else
11652  {
11653  Utilities->CallLogPop(198);
11654  return ItPair.first->second;
11655  }
11656 }
11657 
11658 // ---------------------------------------------------------------------------
11659 
11660 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
11661 {
11662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
11663  bool ErasedFlag = false;
11664 
11665  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
11666  {
11667  if(PrefDirSize() == 0)
11668  {
11669  Utilities->CallLogPop(1511);
11670  return;
11671  }
11672  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
11673  {
11674  ErasedFlag = false;
11675  // use 'else' to ensure don't try to access an erased element
11676  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
11677  {
11678  ErasePrefDirElementAt(11, x);
11679  ErasedFlag = true;
11680  }
11681  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
11682  {
11683  ErasePrefDirElementAt(12, x);
11684  ErasedFlag = true;
11685  }
11686  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
11687  {
11688  ErasePrefDirElementAt(13, x);
11689  ErasedFlag = true;
11690  }
11691  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
11692  {
11693  ErasePrefDirElementAt(9, x);
11694  ErasedFlag = true;
11695  }
11696  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
11697  {
11698  ErasePrefDirElementAt(10, x);
11699  ErasedFlag = true;
11700  }
11701  if(!ErasedFlag)
11702  {
11703  // don't use 'else' here as may be more than one that need decrementing
11704  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
11705  {
11706  PrefDirVector.at(x).TrackVectorPosition--;
11707  }
11708  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
11709  {
11710  PrefDirVector.at(x).Conn[0]--;
11711  }
11712  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
11713  {
11714  PrefDirVector.at(x).Conn[1]--;
11715  }
11716  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
11717  {
11718  PrefDirVector.at(x).Conn[2]--;
11719  }
11720  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
11721  {
11722  PrefDirVector.at(x).Conn[3]--;
11723  }
11724  }
11725  }
11726  }
11727  Utilities->CallLogPop(1434);
11728 }
11729 
11730 // ---------------------------------------------------------------------------
11731 
11732 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
11733 {
11734  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
11735  OverallDistance = 0;
11736  OverallSpeedLimit = 0;
11737  LeadingPointsAtLastElement = false;
11738  if(PrefDirSize() == 0) // shouldn't be empty when this called
11739  {
11740  Utilities->CallLogPop(1491);
11741  return;
11742  }
11743 
11744  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
11745  {
11746  LeadingPointsAtLastElement = true;
11747  Utilities->CallLogPop(1492);
11748  return;
11749  }
11750  for(unsigned int x = 0; x < PrefDirSize(); x++)
11751  {
11752  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
11753  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
11754  {
11755  OverallDistance += PrefDirElement.Length23;
11756  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
11757  {
11758  if(x == 0)
11759  {
11760  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
11761  }
11762  else
11763  {
11764  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
11765  {
11766  OverallSpeedLimit = -1;
11767  }
11768  }
11769  }
11770  }
11771  else
11772  {
11773  OverallDistance += PrefDirElement.Length01;
11774  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
11775  {
11776  if(x == 0)
11777  {
11778  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
11779  }
11780  else
11781  {
11782  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
11783  {
11784  OverallSpeedLimit = -1;
11785  }
11786  }
11787  }
11788  }
11789  }
11790  Utilities->CallLogPop(1529);
11791 }
11792 
11793 // ---------------------------------------------------------------------------
11794 
11795 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
11796 {
11797  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
11798  if(PrefDirSize() == 0)
11799  {
11800  Utilities->CallLogPop(1564);
11801  return;
11802  }
11803 
11804  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11805  bool FoundFlag;
11807  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
11808 
11809  while(MMIT != PrefDir4MultiMap.end())
11810  {
11811  HLoc = MMIT->first.first;
11812  VLoc = MMIT->first.second;
11813  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11814  H = HLoc - Track->GetHLocMin();
11815  V = VLoc - Track->GetVLocMin();
11816  // always found in order, any missing have PrefDirPosx == -1
11817  if(PrefDirPos0 > -1)
11818  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
11819  if(PrefDirPos1 > -1)
11820  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
11821  if(PrefDirPos2 > -1)
11822  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
11823  if(PrefDirPos3 > -1)
11824  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
11825  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
11826  { // need to plot all 4 in order to obtain all the direction graphics
11827  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11828  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11829  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11830  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11831  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11832  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11833  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
11834  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
11835  MMIT++;
11836  MMIT++;
11837  MMIT++;
11838  MMIT++;
11839  }
11840  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
11841  {
11842  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11843  { // 0 & 1 constitute the bidirectional PrefDir
11844  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11845  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11846  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11847  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11848  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
11849  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
11850  MMIT++;
11851  MMIT++;
11852  MMIT++;
11853  }
11854  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
11855  { // 0 & 2 constitute the bidirectional PrefDir
11856  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11857  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11858  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11859  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11860  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11861  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11862  MMIT++;
11863  MMIT++;
11864  MMIT++;
11865  }
11866  else
11867  { // 1 & 2 constitute the bidirectional PrefDir
11868  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11869  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11870  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11871  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11872  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11873  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11874  MMIT++;
11875  MMIT++;
11876  MMIT++;
11877  }
11878  }
11879  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
11880  {
11881  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11882  { // 0 & 1 constitute the bidirectional PrefDir
11883  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11884  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11885  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11886  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11887  MMIT++;
11888  MMIT++;
11889  }
11890  else
11891  { // 2 unidirectional PrefDirs
11892  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11893  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11894  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11895  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11896  MMIT++;
11897  MMIT++;
11898  }
11899  }
11900  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
11901  {
11902  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11903  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11904  MMIT++;
11905  }
11906  }
11907  Utilities->CallLogPop(1565);
11908 }
11909 
11910 // ---------------------------------------------------------------------------
11911 
11912 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
11913 /*
11914  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
11915  level crossing, signals with wrong direction set, or buffers.
11916 */
11917 {
11918  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
11919  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11920  bool FoundFlag;
11922  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
11923 
11924  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
11925  ElementIn.VLoc)))
11926  {
11927  Utilities->CallLogPop(1982);
11928  return false;
11929  }
11930  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
11931  {
11932  Utilities->CallLogPop(1983);
11933  return false;
11934  }
11935  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
11936  {
11937  Utilities->CallLogPop(1995);
11938  return false;
11939  }
11940 // Now check that there is only a single prefdir set
11941  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11942 // always found in order, any missing have PrefDirPosx == -1
11943  if(PrefDirPos0 > -1)
11944  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
11945  if(PrefDirPos1 > -1)
11946  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
11947  if(PrefDirPos2 > -1)
11948  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
11949  if(PrefDirPos3 > -1)
11950  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
11951 
11952  if(PrefDirPos3 > -1) // 4 found, all bidirectional
11953  {
11954  Utilities->CallLogPop(1984);
11955  return false;
11956  }
11957  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
11958  {
11959  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
11960  {
11961  Utilities->CallLogPop(1985);
11962  return false;
11963  }
11964  else
11965  {
11966  Utilities->CallLogPop(1986);
11967  return true;
11968  }
11969  }
11970  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
11971  {
11972  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
11973  {
11974  Utilities->CallLogPop(1987);
11975  return false;
11976  }
11977  else
11978  {
11979  Utilities->CallLogPop(1988);
11980  return true;
11981  }
11982  }
11983  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
11984  {
11985  if(PrefDirElement0.XLinkPos == EntryPos)
11986  {
11987  Utilities->CallLogPop(1989);
11988  return false;
11989  }
11990  else
11991  {
11992  Utilities->CallLogPop(1990);
11993  return true;
11994  }
11995  }
11996  else
11997  {
11998  Utilities->CallLogPop(1991);
11999  return false; // none found
12000  }
12001 }
12002 
12003 // ---------------------------------------------------------------------------
12004 
12006 {
12007 /* //Added at v2.1.0
12008  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
12009  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
12010  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
12011  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
12012  and can be modelled better anyway.
12013 
12014  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
12015  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
12016  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12017  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12018  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12019  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12020 */
12021  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
12022  ElementIn.VLoc + "," + XLink);
12023  int TrackVecPos;
12024  bool TrackFoundFlag;
12025  TTrackElement TempTrackElement;
12026 
12027  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
12028  {
12029  Utilities->CallLogPop(2047);
12030  return false;
12031  }
12032 
12033 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12034  if(XLink == 1)
12035  {
12036  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12037  if(TrackFoundFlag)
12038  {
12039  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
12040  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12041  {
12042  Utilities->CallLogPop(2048);
12043  return true;
12044  }
12045  }
12046  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12047  if(TrackFoundFlag)
12048  {
12049  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
12050  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12051  {
12052  Utilities->CallLogPop(2049);
12053  return true;
12054  }
12055  }
12056  }
12057 
12058 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12059  if(XLink == 3)
12060  {
12061  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12062  if(TrackFoundFlag)
12063  {
12064  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
12065  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12066  {
12067  Utilities->CallLogPop(2050);
12068  return true;
12069  }
12070  }
12071  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12072  if(TrackFoundFlag)
12073  {
12074  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
12075  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12076  {
12077  Utilities->CallLogPop(2051);
12078  return true;
12079  }
12080  }
12081  }
12082 
12083 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12084  if(XLink == 7)
12085  {
12086  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12087  if(TrackFoundFlag)
12088  {
12089  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
12090  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12091  {
12092  Utilities->CallLogPop(2052);
12093  return true;
12094  }
12095  }
12096  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12097  if(TrackFoundFlag)
12098  {
12099  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
12100  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12101  {
12102  Utilities->CallLogPop(2053);
12103  return true;
12104  }
12105  }
12106  }
12107 
12108 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12109  if(XLink == 9)
12110  {
12111  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12112  if(TrackFoundFlag)
12113  {
12114  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
12115  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12116  {
12117  Utilities->CallLogPop(2054);
12118  return true;
12119  }
12120  }
12121  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12122  if(TrackFoundFlag)
12123  {
12124  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
12125  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12126  {
12127  Utilities->CallLogPop(2055);
12128  return true;
12129  }
12130  }
12131  }
12132  Utilities->CallLogPop(2056);
12133  return false;
12134 }
12135 
12136 // ---------------------------------------------------------------------------
12137 
12138 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
12139 {
12140 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
12141  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
12142  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
12143  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
12144  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
12145 */
12146  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
12148  bool FoundFlag, ContFlag, FoundElements = false;
12149  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12150  TPrefDirElement NextElement;
12151 
12152  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
12153  {
12154  LastIteratorValue++;
12155  ContFlag = false;
12156  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
12157  continue;
12158  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
12159  continue;
12160 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
12161  // found a potential route start point
12162  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
12163  {
12164  continue;
12165  }
12166  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
12167  {
12168  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
12169  if(PDVIt->TrackType == Continuation)
12170  {
12171  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
12172  {
12173  continue;
12174  }
12175  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
12176  {
12177  continue;
12178  }
12179  }
12180  StartElement = *PDVIt;
12181 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
12182  // diverging track on which there was no pref dir. See below for 2 required changes.
12183  }
12184  else
12185  {
12186  continue;
12187  }
12188  // now track along until find a signal or continuation, checking validity for each element
12189  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
12190  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
12191  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12192  if(PrefDirPos0 == -1) // no continuing prefdir
12193  {
12194  continue;
12195  }
12196  bool NextElementFoundFlag = false;
12197  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12198  {
12199  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
12200  NextElementFoundFlag = true;
12201  }
12202  if(PrefDirPos1 > -1)
12203  {
12204  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12205  {
12206  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
12207  NextElementFoundFlag = true;
12208  }
12209  }
12210  if(PrefDirPos2 > -1)
12211  {
12212  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12213  {
12214  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
12215  NextElementFoundFlag = true;
12216  }
12217  }
12218  if(PrefDirPos3 > -1)
12219  {
12220  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12221  {
12222  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
12223  NextElementFoundFlag = true;
12224  }
12225  }
12226  if(!NextElementFoundFlag)
12227  {
12228  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12229 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
12230  }
12231  while(true)
12232  {
12233  // check validity
12234  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
12235  {
12236  ContFlag = true;
12237  break;
12238  }
12239  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
12240  {
12241  ContFlag = true;
12242  break;
12243  }
12244  // check if in a route, providing not a signal, as a signal might be at the start of a route
12245  if(NextElement.TrackType != SignalPost)
12246  {
12247  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
12248  {
12249  ContFlag = true;
12250  break;
12251  }
12252  }
12253  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
12254  // can't be a gound signal as would have failed the validity test
12255  {
12256  EndElement = NextElement;
12257  break;
12258  }
12259  // get the next element in the sequence
12260  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
12261  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
12262  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12263  if(PrefDirPos0 == -1) // no continuing prefdir
12264  {
12265  ContFlag = true;
12266  break;
12267  }
12268  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12269  {
12270  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
12271  continue;
12272  }
12273  if(PrefDirPos1 > -1)
12274  {
12275  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12276  {
12277  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
12278  continue;
12279  }
12280  }
12281  if(PrefDirPos2 > -1)
12282  {
12283  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12284  {
12285  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
12286  continue;
12287  }
12288  }
12289  if(PrefDirPos3 > -1)
12290  {
12291  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12292  {
12293  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
12294  continue;
12295  }
12296  }
12297  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
12298  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
12299  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
12300  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
12301  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
12302  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
12303  {
12304  ContFlag = true;
12305  break;
12306  }
12307  else
12308  {
12309  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12310  // could drop the bridge test but keep it to show the change history
12311  break;
12312 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
12313  }
12314  }
12315  if(ContFlag)
12316  continue;
12317  // else have start and end elements set & all elements valid, so set up the route segment
12318  FoundElements = true;
12319  break;
12320  }
12321  if(FoundElements)
12322  {
12323  Utilities->CallLogPop(1992);
12324  return true;
12325  }
12326  else
12327  {
12328  Utilities->CallLogPop(1993);
12329  return false;
12330  }
12331 }
12332 
12333 // ---------------------------------------------------------------------------
12334 // TOneRoute
12335 // ---------------------------------------------------------------------------
12336 
12337 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
12338 {
12339 /* General:
12340  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
12341  containing all the new elements to form the route. When complete, the SearchVector is converted into route
12342  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
12343  route will use automatic signals or not.
12344  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
12345  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
12346  elements, so additional work is needed to complete all their members before they are ready for conversion into
12347  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
12348  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
12349  ConvertAndAdd.......
12350 
12351  Note that originally intended to allow preferred routes without consecutive signals, hence ConsecSignalsRoute flag.
12352  Later decided to enforce ConsecSignalsRoute for preferred routes, but left original code as was.
12353 
12354  Specific:
12355 
12356  Function returns true for a valid start element, false, with a message, if not.
12357  ClearRoute to empty both PrefDirVector & SearchVector
12358  Check selection matches a TrackElement & ensure a signal/buffers/continuation if using ConsecSignals,
12359  else disallow points, bridge or crossover.
12360  Disallow if train on element.
12361 
12362  Set default values for parameters that are retained in AllRoutes:-
12363  StartSelectionRouteID = route that selection starts in or adjacent to end of;
12364  StartRoutePosition = trackvectornumber of the element to be used as the start of the route;
12365  StartElement1 = the 1st or only TPrefDirElement of the route start element
12366  StartElement2 = the 2nd (if exists) TPrefDirElement of the start element (can be a max of 2 PrefDirs for
12367  a given selection that isn't points, bridge or crossover;
12368 
12369  Check selection corresponds to at least 1 PrefDir element in EveryPrefDir & set StartElement1 & possibly also 2. If
12370  signal/buffers/continuation for ConsecSignalsRoute, or buffers/continuation for not ConsecSignalsRoute,
12371  ensure the PrefDir corresponds to the direction of the signal or away from the buffers/continuation.
12372  Check if in an existing route. Disallow if start anywhere except at end of the route, if the route end is an 'End'
12373  configuration (nowhere to go), and if the end of the route links forwards into another route.
12374  If these tests passed set StartSelectionRouteID, StartElement1 and StartRoutePosition to correspond to the route end element
12375  and blank StartElement2 (only want to use the route element), then return true.
12376  Check also that doesn't lie in >1 route & give error message if so - should never happen.
12377  Check if adjacent to start or end of an existing route & disallow.
12378  The start element (with AutoSignals member set as AutoSigs flag) is stored in SearchVector, unless an existing route element is to
12379  be used as the start element.
12380 */
12381  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
12382  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
12383  ClearRoute();
12384  int TrackVectorPosition;
12385  TTrackElement TrackElement;
12386  TPrefDirElement FirstElement, LastElement;
12387 
12388  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12389  {
12390  Utilities->CallLogPop(199);
12391  return false;
12392  }
12393  if(ConsecSignalsRoute)
12394  {
12395  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
12396  {
12397  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
12398  Utilities->CallLogPop(1996);
12399  return false;
12400  }
12401  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12402  {
12403  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
12404  Utilities->CallLogPop(200);
12405  return false;
12406  }
12407  }
12408  else
12409  {
12410  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
12411  {
12412  TrainController->StopTTClockMessage(8, "Can't select points, bridge or crossover when route building");
12413 // makes later adjacent route checks too complicated
12414  Utilities->CallLogPop(201);
12415  return false;
12416  }
12417  }
12418 
12419  if(Track->IsLCAtHV(18, HLoc, VLoc))
12420  {
12421  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
12422  Utilities->CallLogPop(1909);
12423  return false;
12424  }
12425 
12426 // check if selected a train & disallow if so
12427  if(TrackElement.TrainIDOnElement > -1)
12428  {
12429  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
12430  Utilities->CallLogPop(202);
12431  return false;
12432  }
12433 
12434 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
12435  TPrefDirElement PrefDirElement;
12436  int LockedVectorNumber;
12437 
12438  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
12439  {
12440  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
12441  Utilities->CallLogPop(203);
12442  return false;
12443  }
12444  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
12445  {
12446  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
12447  Utilities->CallLogPop(204);
12448  return false;
12449  }
12450 
12452  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
12453 // signal in an autosig route & follow with a non-autosig route
12454 
12455  TPrefDirElement BlankElement;
12456 
12457  StartElement1 = BlankElement;
12458  StartElement2 = BlankElement;
12459 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
12460  bool InPrefDirFlag = false;
12461 
12462  bool FoundFlag;
12463  int PrefDirPos0 = -1;
12464  int PrefDirPos1 = -1;
12465  int PrefDirPos2 = -1;
12466  int PrefDirPos3 = -1;
12467 
12469  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12470  int PrefDirVecPos[4] =
12471  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
12472 
12473  for(int x = 0; x < 4; x++)
12474  {
12475  int b = PrefDirVecPos[x];
12476  if(b > -1)
12477  {
12478  if(ConsecSignalsRoute)
12479  {
12480  // only allow the appropriate exit route to be searched
12481  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
12482  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
12483  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
12484  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
12485  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
12486  {
12487  InPrefDirFlag = true;
12488  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
12489  if(AutoSigsFlag)
12490  {
12491  StartElement1.AutoSignals = true;
12492  }
12494  StartElement2 = BlankElement;
12495  }
12496  }
12497  else
12498  {
12499  // only allow the appropriate exit route to be searched
12500  // AutoSignals & ConsecSignals stay false for not ConsecSignalsRoute
12501  if(((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(22, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(23,
12502  b).XLinkPos] == Connection)) || ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(24,
12503  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(25, b).XLinkPos] == Connection)))
12504  {
12505  InPrefDirFlag = true;
12506  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(26, b);
12507  StartElement2 = BlankElement;
12508  }
12509  else if((TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12510  {
12511  InPrefDirFlag = true;
12513  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(27, b);
12514  else
12515  StartElement2 = EveryPrefDir->GetFixedPrefDirElementAt(28, b);
12516  }
12517  }
12518  }
12519  }
12520 
12521  if(!InPrefDirFlag)
12522  {
12524  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
12525  Utilities->CallLogPop(205);
12526  return false;
12527  }
12528 
12529 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
12531  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
12532 
12533  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
12534  {
12535  throw Exception("Selection in two routes - should never happen!");
12536  }
12537 
12538  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
12539  {
12540  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
12541  {
12542  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
12543  Utilities->CallLogPop(206);
12544  return false;
12545  }
12546  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
12547  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
12548  {
12549  TrainController->StopTTClockMessage(14, "No forward connection from this position");
12550  Utilities->CallLogPop(207);
12551  return false;
12552  }
12553  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
12554  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
12555  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
12556  {
12557  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
12558  Utilities->CallLogPop(208);
12559  return false;
12560  }
12561  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
12563  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
12564  if(AutoSigsFlag)
12565  {
12566  StartElement1.AutoSignals = true;
12567  }
12568  if(ConsecSignalsRoute)
12569  {
12571  }
12572  StartElement2 = BlankElement; // only use the route element
12574  Utilities->CallLogPop(209);
12575  return true; // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
12576  }
12577 
12578  else // no route started
12579  {
12580 // check if selected position is adjacent to start or end of an existing route and disallow
12581  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
12582  {
12583  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
12584  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
12585  {
12586  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
12587  Utilities->CallLogPop(210);
12588  return false;
12589  }
12590  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
12591  {
12592  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
12593  Utilities->CallLogPop(211);
12594  return false;
12595  }
12596  }
12597 
12598 // check if it's adjacent to end of an an existing route,
12599  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
12600  {
12602  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
12603  {
12604  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
12605  Utilities->CallLogPop(212);
12606  return false;
12607  }
12608  }
12609  SearchVector.push_back(StartElement1);
12610  Utilities->CallLogPop(213);
12611  return true;
12612  }
12613 }
12614 
12615 // ---------------------------------------------------------------------------
12616 
12617 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag,
12618  IDInt &ReqPosRouteID, bool &PointsChanged)
12619 
12620 /*
12621  [Note this was written when it was intended to have routes confined to preferred direction elements but with a choice of whether
12622  they had to run from signal to signal (bool ConsecSignalsRoute true), or not (bool ConsecSignalsRoute false), as well as using
12623  automatic signals or not. Since then it was decided only to allow these routes to run from signal to signal, so ConsecSignalsRoute
12624  is always true when this routine is called. The routine could be made much simpler, but has been left as is because it works (at
12625  least it has done so far), and it allows the original option to be used if it ever seems appropriate in the future.]
12626  *
12627  Return true if select valid next element, in which case the route is set & stored. Return false for an invalid next element.
12628  *
12629  Declare integers EndPosition (the position used) and
12630  ReqPosRouteID to hold (when required) the existing route selected, this being set to -1 for not used.
12631  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
12632  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
12633  Check correct type of element - signal/buffers/continuation if ConsecSignalsRoute, else not points, bridge or crossover.
12634  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
12635  EndElement2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2 above).
12636  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
12637  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
12638  linked forward to another route.
12639  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
12640  for same position as start should cover this)
12641  *
12642  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
12643  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
12644  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
12645  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
12646  If the search fails the return false.
12647  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
12648  in the SearchVector to ensure it's entered as part of the new route.
12649  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
12650  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
12651  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed set
12652  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
12653  so return false, with an appropriate message if ConsecSignalsRoute set.
12654 */
12655 
12656 {
12657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
12658  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
12659  int EndPosition; // the position selected
12660 
12661  Track->LCFoundInAutoSigsRoute = false;
12663  TotalSearchCount = 0;
12664  ReqPosRouteID = IDInt(-1); // default value for not used
12665  TTrackElement TrackElement;
12666  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
12667 
12668  // given element as can't select 2-track elements
12669  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
12670  {
12671  Utilities->CallLogPop(214);
12672  return false;
12673  }
12674 
12675  if(Track->IsLCAtHV(19, HLoc, VLoc))
12676  {
12677  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
12678  Utilities->CallLogPop(1908);
12679  return false;
12680  }
12681 
12682 // cancel selection if on original start element
12683  if(EndPosition == StartRoutePosition)
12684  {
12685  Utilities->CallLogPop(215);
12686  return false;
12687  }
12688  if(AutoSigsFlag)
12689  {
12690  if(TrackElement.TrackType == Buffers)
12691  {
12692  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
12693  Utilities->CallLogPop(216);
12694  return false;
12695  }
12696  }
12697  if(ConsecSignalsRoute)
12698  {
12699  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12700  {
12701  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
12702  Utilities->CallLogPop(217);
12703  return false;
12704  }
12705  }
12706  else // not needed now can't have preferred non-consec signals routes, but leave in
12707  {
12708  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
12709  {
12710  TrainController->StopTTClockMessage(21, "Can't select points, bridge or crossover when building a route");
12711 // makes later adjacent route checks too complicated
12712  Utilities->CallLogPop(218);
12713  return false;
12714  }
12715  }
12716 
12717 // check if train on element
12718  if(TrackElement.TrainIDOnElement > -1)
12719  {
12720  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
12721  Utilities->CallLogPop(219);
12722  return false;
12723  }
12724 
12725 // disallow if not in EveryPrefDir & set EndElement(s)
12726  bool InPrefDirFlag = false;
12727 
12728  bool FoundFlag;
12729  int PrefDirPos0 = -1;
12730  int PrefDirPos1 = -1;
12731  int PrefDirPos2 = -1;
12732  int PrefDirPos3 = -1;
12733 
12734  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
12735  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12736  int PrefDirVecPos[4] =
12737  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
12738 
12739  for(int x = 0; x < 4; x++)
12740  {
12741  int b = PrefDirVecPos[x];
12742  if(b > -1)
12743  {
12744  InPrefDirFlag = true;
12745  if(EndElement1.TrackVectorPosition == -1)
12746  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
12747  else
12748  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
12749  }
12750  }
12751  if(!InPrefDirFlag)
12752  {
12754  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
12755  Utilities->CallLogPop(220);
12756  return false;
12757  }
12758 
12759 // check if in an existing route - can't be a bridge so can use a simple 'find'
12760 // bool InRoute = false;
12762  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
12763 
12764  if(RoutePair.first > -1)
12765  {
12766  if(RoutePair.second != 0) // not first element in existing route so no good
12767  {
12768  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
12769  Utilities->CallLogPop(221);
12770  return false;
12771  }
12772  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
12773 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
12774  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
12775  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
12776  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
12777  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
12778  {
12779  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
12780  Utilities->CallLogPop(222);
12781  return false;
12782  }
12783  EndElement1 = RouteElement;
12784  EndElement2 = BlankElement; // only need the route element
12785  EndPosition = EndElement1.TrackVectorPosition;
12786  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
12787  }
12788 
12789 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12790 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12791 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12792 
12793  if(EndElement1.HLoc >= StartElement1.HLoc)
12794  {
12796  SearchLimitHighH = EndElement1.HLoc + 15;
12797  }
12798  else
12799  {
12800  SearchLimitLowH = EndElement1.HLoc - 15;
12802  }
12803 
12804  if(EndElement1.VLoc >= StartElement1.VLoc)
12805  {
12807  SearchLimitHighV = EndElement1.VLoc + 15;
12808  }
12809  else
12810  {
12811  SearchLimitLowV = EndElement1.VLoc - 15;
12813  }
12814 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
12815  check & TotalSearchCounts check
12816  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
12817  {
12818  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
12819  Utilities->CallLogPop(1693);
12820  return false;
12821  }
12822 */
12823 // check if adjacent to start and disallow
12824  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
12825  {
12827  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
12828 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
12829 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
12830  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
12831  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
12832  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
12833  {
12834  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
12835  Utilities->CallLogPop(223);
12836  return false;
12837  }
12838 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
12839 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
12840  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
12841  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
12842  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
12843  {
12844  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
12845  Utilities->CallLogPop(224);
12846  return false;
12847  }
12848 
12849 // check if adjacent to end of a route & disallow
12851  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
12852  {
12853  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
12854  Utilities->CallLogPop(225);
12855  return false;
12856  }
12857  }
12858 
12859 // check for same route as start element
12861  {
12862  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
12863  Utilities->CallLogPop(226);
12864  return false;
12865  }
12866 
12867 // check for a looping route
12868  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
12869  {
12871  {
12872  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
12873  Utilities->CallLogPop(1844);
12874  return false;
12875  }
12876  }
12877 
12878 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
12879 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
12880 // and don't want to add it again
12881  if(StartSelectionRouteID > -1)
12882  {
12883  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12884  AutoSigsFlag))
12885  {
12886  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
12887  if(PointsToBeChanged(5))
12888  {
12889  PointsChanged = true;
12890  }
12891  Utilities->CallLogPop(227);
12892  return true;
12893  }
12894  else if(ConsecSignalsRoute && !Track->LCFoundInAutoSigsRouteMessageGiven)
12896  Utilities->CallLogPop(228);
12897  return false;
12898  }
12899  else
12900  {
12901 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
12902 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
12903 
12904 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
12905 // note that a blank element will have XLinkPos set to -1
12906  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
12907  {
12908  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12909  AutoSigsFlag))
12910  {
12911  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
12912  if(PointsToBeChanged(6))
12913  {
12914  PointsChanged = true;
12915  }
12916  Utilities->CallLogPop(229);
12917  return true;
12918  }
12919  else
12920  {
12923  Utilities->CallLogPop(230);
12924  return false;
12925  }
12926  }
12927  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
12928  {
12929  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12930  AutoSigsFlag))
12931  {
12932  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
12933  if(PointsToBeChanged(7))
12934  {
12935  PointsChanged = true;
12936  }
12937  Utilities->CallLogPop(231);
12938  return true;
12939  }
12940  else
12941  {
12944  Utilities->CallLogPop(232);
12945  return false;
12946  }
12947  }
12948 
12949  // now start off in the best direction
12950  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
12951  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
12952  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
12953  // unless new problems are found.
12954  if(StartElement1.XLinkPos == BestPos)
12955  {
12956  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
12957  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12958  AutoSigsFlag))
12959  {
12960  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
12961  if(PointsToBeChanged(8))
12962  {
12963  PointsChanged = true;
12964  }
12965  Utilities->CallLogPop(233);
12966  return true;
12967  }
12968  else if(StartElement2.TrackVectorPosition > -1)
12969  {
12970  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
12971  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12972  AutoSigsFlag))
12973  {
12974  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
12975  if(PointsToBeChanged(9))
12976  {
12977  PointsChanged = true;
12978  }
12979  Utilities->CallLogPop(234);
12980  return true;
12981  }
12982  }
12983  }
12984  else if(StartElement2.TrackVectorPosition > -1)
12985  {
12986  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
12987  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12988  AutoSigsFlag))
12989  {
12990  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
12991  if(PointsToBeChanged(10));
12992  {
12993  PointsChanged = true;
12994  }
12995  Utilities->CallLogPop(1857);
12996  return true;
12997  }
12998  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12999  AutoSigsFlag))
13000  {
13001  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
13002  if(PointsToBeChanged(11));
13003  {
13004  PointsChanged = true;
13005  }
13006  Utilities->CallLogPop(1858);
13007  return true;
13008  }
13009  }
13010  else if(StartElement1.XLinkPos == (1 - BestPos))
13011  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction
13012  {
13013  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13014  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13015  AutoSigsFlag))
13016  {
13017  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
13018  if(PointsToBeChanged(12))
13019  {
13020  PointsChanged = true;
13021  }
13022  Utilities->CallLogPop(1864);
13023  return true;
13024  }
13025  }
13026  }
13029  Utilities->CallLogPop(235);
13030  return false;
13031 }
13032 
13033 // ---------------------------------------------------------------------------
13034 
13035 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
13036 {
13037  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
13038  if(PrefDirSize() == 0)
13039  {
13040  Utilities->CallLogPop(1704);
13041  return;
13042  }
13043  for(unsigned int x = 0; x < PrefDirSize(); x++)
13044  {
13045  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13046  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13047  {
13048  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13049  TempPrefDirElement.EXGraphicPtr);
13050  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
13051  {
13052  if(x == 0)
13053  {
13054  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13055  TempPrefDirElement.EntryDirectionGraphicPtr);
13056  }
13057  if(x == (PrefDirSize() - 1))
13058  {
13059  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13060  TempPrefDirElement.EntryDirectionGraphicPtr);
13061  }
13062  }
13063  }
13064  }
13065 
13066  Utilities->CallLogPop(1705);
13067 }
13068 
13069 // ---------------------------------------------------------------------------
13070 
13071 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
13072  TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndPosition, bool AutoSigsFlag)
13073 
13074 /*
13075  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
13076  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If
13077  it's an element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
13078  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
13079  Return false if any element (apart from RequiredPosition) is on an existing route.
13080  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point).
13081 
13082  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
13083  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
13084  added during the function so as to leave it exactly as it was on entering, then return false).
13085  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
13086  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
13087  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
13088  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
13089  the route number that the searched-for element is the start of if any, and set to -1 if no
13090  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
13091  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
13092  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
13093  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
13094 
13095  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
13096  or a continuation, and fail if so. Check if reached a valid signal in ConsecSignalsRoute on any but firstpass
13097  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
13098  for recursive calls), and fail if so as user should always select the next signal in a route.
13099  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
13100  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
13101  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
13102  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
13103  or if train on element (unless a bridge & train on different track).
13104  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
13105  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
13106  a leading point where both trailing directions are in EveryPrefDir, if not fail.
13107  Check if found RequiredPosition & that it's a signal/buffer/continuation if ConsecSignalsRoute set. If OK save in SearchVector with
13108  AutoSignals member set if AutoSigsFlag set, then return true.
13109  Check & fail if a buffer or continuation (if element = RequiredPosition will have succeeded in the above check.
13110 
13111  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
13112  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
13113  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
13114  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
13115  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
13116  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
13117  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
13118 
13119  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
13120  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
13121 */
13122 
13123 {
13124  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
13125  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
13126  AnsiString((short)AutoSigsFlag));
13127  int VectorCount = 0;
13128  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
13129 
13130 // check for a fouled diagonal for first element. Added for v1.3.2
13131  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
13132  {
13133  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
13134  {
13135  for(int x = 0; x < VectorCount; x++)
13136  SearchVector.erase(SearchVector.end() - 1);
13137  Utilities->CallLogPop(2043);
13138  return false;
13139  }
13140  }
13141 
13142  bool FirstPass = true;
13143 
13144  while(true)
13145  {
13146  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
13147  {
13148  Track->LCFoundInAutoSigsRoute = true;
13149  }
13150  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
13151  {
13152  for(int x = 0; x < VectorCount; x++)
13153  SearchVector.erase(SearchVector.end() - 1);
13154  Utilities->CallLogPop(1926);
13155  return false;
13156  }
13157  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
13158  {
13159  for(int x = 0; x < VectorCount; x++)
13160  SearchVector.erase(SearchVector.end() - 1);
13161  Utilities->CallLogPop(236);
13162  return false;
13163  }
13164  if(!FirstPass && (ConsecSignalsRoute) && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
13165  // reached a valid signal that isn't the required position, user should always select the next
13166  // signal in a route so have to fail
13167  // won't affect recurive searches as for them the first pass element is always a point
13168  {
13169  for(int x = 0; x < VectorCount; x++)
13170  SearchVector.erase(SearchVector.end() - 1);
13171  Utilities->CallLogPop(237);
13172  return false;
13173  }
13174  FirstPass = false;
13175  int NextPosition = PrefDirElement.Conn[XLinkPos];
13176  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
13177  TPrefDirElement SearchElement(NextTrackElement);
13178  SearchElement.TrackVectorPosition = NextPosition;
13179  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
13180  SearchElement.ELinkPos = NextELinkPos;
13181  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
13182  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
13183  int NextXLinkPos;
13184  if(SearchElement.ELinkPos == 0)
13185  NextXLinkPos = 1;
13186  if(SearchElement.ELinkPos == 1)
13187  NextXLinkPos = 0;
13188  if(SearchElement.ELinkPos == 2)
13189  NextXLinkPos = 3;
13190  if(SearchElement.ELinkPos == 3)
13191  NextXLinkPos = 2;
13192  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
13193  {
13194  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
13195 // note that may be buffers, continuation or gap
13196  SearchElement.XLinkPos = NextXLinkPos;
13197  }
13198 // can't set XLink or XLinkPos yet if the element is a leading point.
13199 
13200 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
13201  for(unsigned int x = 0; x < SearchVector.size(); x++)
13202  {
13203  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
13204  {
13205  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
13206  // OK if a bridge & routes on different tracks
13207  {
13208  for(int x = 0; x < VectorCount; x++)
13209  SearchVector.erase(SearchVector.end() - 1);
13210  Utilities->CallLogPop(238);
13211  return false;
13212  }
13213  }
13214  }
13215 
13216 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
13217  TAllRoutes::TRouteElementPair SecondPair;
13219  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
13220  if(RoutePair.first > -1)
13221  {
13222  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13223  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
13224  RoutePair.second).ELinkPos)))
13225  {
13226  // still OK if start of an expected route
13227  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
13228  {
13229  for(int x = 0; x < VectorCount; x++)
13230  SearchVector.erase(SearchVector.end() - 1);
13231  Utilities->CallLogPop(239);
13232  return false; // only allow for start of an expected route
13233  }
13234  }
13235  }
13236  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
13237  {
13238  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13239  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
13240  SecondPair.second).ELinkPos)))
13241  {
13242  // still OK if start of an expected route
13243  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
13244  {
13245  for(int x = 0; x < VectorCount; x++)
13246  SearchVector.erase(SearchVector.end() - 1);
13247  Utilities->CallLogPop(240);
13248  return false; // only allow for start of an expected route
13249  }
13250  }
13251  }
13252 
13253 // check if a train on element, unless a bridge & train on different track
13254 // OK of same train as start element - no drop this
13255 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
13256  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
13257  {
13258  for(int x = 0; x < VectorCount; x++)
13259  SearchVector.erase(SearchVector.end() - 1);
13260  Utilities->CallLogPop(241);
13261  return false;
13262  }
13263  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
13264  {
13265  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
13266  {
13267  for(int x = 0; x < VectorCount; x++)
13268  SearchVector.erase(SearchVector.end() - 1);
13269  Utilities->CallLogPop(242);
13270  return false;
13271  }
13272  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
13273  {
13274  for(int x = 0; x < VectorCount; x++)
13275  SearchVector.erase(SearchVector.end() - 1);
13276  Utilities->CallLogPop(243);
13277  return false;
13278  }
13279  }
13280 
13281 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
13282  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13283  {
13284  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13285  {
13286  for(int x = 0; x < VectorCount; x++)
13287  SearchVector.erase(SearchVector.end() - 1);
13288  Utilities->CallLogPop(244);
13289  return false;
13290  }
13291  }
13292 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
13293 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
13294  bool InPrefDirFlag = false;
13295  PrefDirElement1 = BlankElement;
13296  PrefDirElement2 = BlankElement;
13297 
13298  bool FoundFlag;
13299  int PrefDirPos0 = -1;
13300  int PrefDirPos1 = -1;
13301  int PrefDirPos2 = -1;
13302  int PrefDirPos3 = -1;
13304  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13305  int PrefDirVecPos[4] =
13306  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13307  for(int x = 0; x < 4; x++)
13308  {
13309  int b = PrefDirVecPos[x];
13310  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
13311  {
13312  InPrefDirFlag = true;
13313  if(PrefDirElement1.TrackVectorPosition == -1)
13314  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
13315  else
13316  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
13317  }
13318  }
13319  if(!InPrefDirFlag)
13320  {
13321  for(int x = 0; x < VectorCount; x++)
13322  SearchVector.erase(SearchVector.end() - 1);
13323  Utilities->CallLogPop(245);
13324  return false;
13325  }
13326 
13327 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
13328 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
13329 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13331  {
13332  for(int x = 0; x < VectorCount; x++)
13333  SearchVector.erase(SearchVector.end() - 1);
13334  Utilities->CallLogPop(1690);
13335  return false;
13336  }
13337 
13338 // check if found it
13339  if(SearchElement.TrackVectorPosition == RequiredPosition)
13340  {
13341 // need to ensure a signal/buffer/continuation if ConsecSignalsRoute set,
13342  if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
13343  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
13344  {
13345  for(int x = 0; x < VectorCount; x++)
13346  SearchVector.erase(SearchVector.end() - 1);
13347  Utilities->CallLogPop(246);
13348  return false;
13349  } // if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal).......
13350  if(AutoSigsFlag)
13351  {
13352  PrefDirElement1.AutoSignals = true;
13353  }
13354  if(ConsecSignalsRoute)
13355  {
13356  PrefDirElement1.ConsecSignals = true;
13357  }
13359  {
13361  {
13362  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
13364  }
13365  for(int x = 0; x < VectorCount; x++)
13366  SearchVector.erase(SearchVector.end() - 1);
13367  Utilities->CallLogPop(1928);
13368  return false;
13369  }
13370  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
13371  VectorCount++; // not really needed but include for tidyness
13372  TotalSearchCount++;
13373  Utilities->CallLogPop(247);
13374  return true;
13375  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
13376 // check if a buffer or continuation (end of search on this leg if not found by now)
13377  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
13378  {
13379  for(int x = 0; x < VectorCount; x++)
13380  SearchVector.erase(SearchVector.end() - 1);
13381  Utilities->CallLogPop(248);
13382  return false;
13383  }
13384 // check if SearchVector exceeds a size of 150
13385  if(SearchVector.size() > 150)
13386  {
13387  for(int x = 0; x < VectorCount; x++)
13388  SearchVector.erase(SearchVector.end() - 1);
13389  Utilities->CallLogPop(1420);
13390  return false;
13391  }
13392 // check if reached a leading point
13393  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13394  {
13395 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
13396  int SearchPos1 = SearchElement.Attribute + 1;
13397  int SearchPos2;
13398  if(SearchPos1 == 2)
13399  SearchPos1++;
13400  if(SearchPos1 == 1)
13401  SearchPos2 = 3;
13402  else
13403  SearchPos2 = 1;
13404  SearchElement.XLink = SearchElement.Link[SearchPos1];
13405  SearchElement.XLinkPos = SearchPos1;
13406  InPrefDirFlag = false;
13407  if(SearchElement.XLink == PrefDirElement1.XLink)
13408  {
13409  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13410  InPrefDirFlag = true;
13411  }
13412  else if(SearchElement.XLink == PrefDirElement2.XLink)
13413  {
13414  SearchElement = PrefDirElement2;
13415  InPrefDirFlag = true;
13416  }
13417 // push element with XLink set to position [SearchPos1] if on a PrefDir
13418  if(InPrefDirFlag)
13419  {
13420 // check for a fouled diagonal for leading point for XLinkPos == 1)
13421  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13422  {
13423  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13424  {
13425  for(int x = 0; x < VectorCount; x++)
13426  SearchVector.erase(SearchVector.end() - 1);
13427  Utilities->CallLogPop(249);
13428  return false;
13429  }
13430  }
13431  if(AutoSigsFlag)
13432  {
13433  SearchElement.AutoSignals = true;
13434  }
13435  if(ConsecSignalsRoute)
13436  {
13437  SearchElement.ConsecSignals = true;
13438  }
13439  SearchVector.push_back(SearchElement);
13440  VectorCount++;
13441  TotalSearchCount++;
13442 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
13443  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13444  AutoSigsFlag))
13445  {
13447  {
13449  {
13450  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
13452  }
13453  for(int x = 0; x < VectorCount; x++)
13454  SearchVector.erase(SearchVector.end() - 1);
13455  Utilities->CallLogPop(1929);
13456  return false;
13457  }
13458  Utilities->CallLogPop(250);
13459  return true;
13460  }
13461  else
13462  {
13463 // remove leading point with XLinkPos [1]
13464  SearchVector.erase(SearchVector.end() - 1);
13465  VectorCount--;
13466  }
13467  }
13468 // XLink set to position [SearchPos2]
13469  SearchElement.XLink = SearchElement.Link[SearchPos2];
13470  SearchElement.XLinkPos = SearchPos2;
13471  if(SearchElement.XLink == PrefDirElement1.XLink)
13472  {
13473  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13474  }
13475  else if(SearchElement.XLink == PrefDirElement2.XLink)
13476  {
13477  SearchElement = PrefDirElement2;
13478  }
13479  else // failed to find a valid exit from the point
13480  {
13481  for(int x = 0; x < VectorCount; x++)
13482  SearchVector.erase(SearchVector.end() - 1);
13483  Utilities->CallLogPop(251);
13484  return false;
13485  }
13486 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
13487  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13488  {
13489  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13490  {
13491  for(int x = 0; x < VectorCount; x++)
13492  SearchVector.erase(SearchVector.end() - 1);
13493  Utilities->CallLogPop(252);
13494  return false;
13495  }
13496  }
13497 // push element with XLink set to position [SearchPos2]
13498  if(AutoSigsFlag)
13499  {
13500  SearchElement.AutoSignals = true;
13501  }
13502  if(ConsecSignalsRoute)
13503  {
13504  SearchElement.ConsecSignals = true;
13505  }
13506  SearchVector.push_back(SearchElement);
13507  VectorCount++;
13508  TotalSearchCount++;
13509 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
13510  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13511  AutoSigsFlag))
13512  {
13514  {
13516  {
13517  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
13519  }
13520  for(int x = 0; x < VectorCount; x++)
13521  SearchVector.erase(SearchVector.end() - 1);
13522  Utilities->CallLogPop(1930);
13523  return false;
13524  }
13525  Utilities->CallLogPop(1592);
13526  return true;
13527  }
13528  else
13529  {
13530  for(int x = 0; x < VectorCount; x++)
13531  SearchVector.erase(SearchVector.end() - 1);
13532  Utilities->CallLogPop(253);
13533  return false;
13534  }
13535  } // if leading point
13536 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
13537  SearchElement = PrefDirElement1;
13538  if(AutoSigsFlag)
13539  {
13540  SearchElement.AutoSignals = true;
13541  }
13542  if(ConsecSignalsRoute)
13543  {
13544  SearchElement.ConsecSignals = true;
13545  }
13546  SearchVector.push_back(SearchElement);
13547  VectorCount++;
13548  TotalSearchCount++;
13549  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
13550  PrefDirElement = SearchElement;
13551  } // while(true)
13552 }
13553 
13554 // ---------------------------------------------------------------------------
13555 
13556 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
13557 {
13558 /*
13559  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
13560  and the new or extended route created from that. Hence action varies depending on whether
13561  it is a completely new route, or an extension of an existing route at the beginning or the end.
13562  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
13563  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
13564 
13565  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
13566  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
13567  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
13568  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
13569  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
13570  is decremented;
13571  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
13572  from the existing route, then enter the new route into the AllRoutesVector;
13573  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
13574  then enter the new route into the AllRoutesVector.
13575 
13576  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
13577  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
13578  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
13579  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
13580  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
13581  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
13582  for the new route and return;
13583  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
13584  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
13585 
13586  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
13587  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
13588  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
13589 */
13590  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
13591  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
13592  if(SearchVector.size() < 1)
13593  {
13594  Utilities->CallLogPop(254);
13595  return;
13596  }
13598  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
13599  {
13600  Utilities->CallLogPop(255);
13601  return;
13602  }
13603 
13604  TAllRoutes::TLockedRouteClass LockedRouteObject;
13605 
13607  unsigned int TruncatePrefDirPosition = 0;
13608 
13609  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
13610 /* if have ReqPosRouteID:
13611  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
13612  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
13613  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
13614  the existing route, then enter the new route into the AllRoutesVector
13615  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
13616  then enter the new route into the AllRoutesVector
13617 */
13618  {
13621  {
13622  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
13623  x++) // start at 1 as first element already in SearchVector
13624  {
13626  }
13627  // note that route numbers in map adjusted when ReqPos route cleared
13629  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
13630  // set during ClearRouteDuringRouteBuildingAt
13632  {
13635  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
13636  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
13637  }
13638  }
13640  {
13642  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
13643  }
13645  {
13646  SearchVector.pop_back();
13647  }
13648  }
13649 
13650  if(StartSelectionRouteID > -1)
13651 /* if have StartSelectionRouteID:
13652  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
13653  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
13654  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
13655  then add it to the start of the new route, then enter the new route into the AllRoutesVector
13656  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
13657 */
13658  {
13660  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
13661  {
13664  {
13665  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
13666  for(unsigned int x = 0; x < SearchVector.size(); x++)
13667  {
13669  RouteNumber, GetFixedSearchElementAt(3, x));
13670  // find & store locked route truncate position in PrefDirVector for later use
13672  {
13673  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
13674  {
13675  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
13676  }
13677  }
13678  }
13680  {
13681  throw Exception("Error - failed to validate extended route for preferred route");
13682  }
13685  if(!AutoSigsFlag)
13686  {
13687  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
13688  }
13689  // now add the reinstated locked route if required and set signals accordingly
13691  {
13692  LockedRouteObject.RouteNumber = RouteNumber;
13693  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
13694  // now reset the signals for the locked route
13695  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
13696  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
13697  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
13698  // return all signals to red in route section to be truncated
13699  {
13700  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
13701  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
13702  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
13703  {
13704  TrackElement.Attribute = 0;
13705  Track->PlotSignal(10, TrackElement, Display);
13706  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
13707  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
13708  }
13709  }
13710  }
13711  AllRoutes->CheckMapAndRoutes(1); // test
13712  Utilities->CallLogPop(256);
13713  return;
13714  }
13716  {
13719  RouteElement.AutoSignals = true;
13720  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
13721  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
13722  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
13723  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
13724  }
13725  }
13726  else
13727  {
13729  }
13730 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
13731 // AllRoutesVector hence nothing to do here
13732  }
13733 
13734  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
13735  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
13736  {
13737  throw Exception("Error - failed to validate single route for preferred route");
13738  }
13739  AllRoutes->StoreOneRoute(1, this);
13740  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
13741  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
13742  if(!AutoSigsFlag)
13743  {
13744  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
13745  }
13746  AllRoutes->CheckMapAndRoutes(2); // test
13747  Utilities->CallLogPop(257);
13748 }
13749 
13750 // ---------------------------------------------------------------------------
13751 
13752 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon) // Return true if OK.
13753 {
13754 /*
13755  [Note: original intention was to allow both consecutive signals and non-consecutive signals for routes
13756  on track with or without pref dirs set, hence the bool ConsecSignalsRoute, subsequently decided to
13757  make all unrestricted routes nonconsecutive signals, so that parameter will always be false. leave
13758  as is in case wish to change at a later time]
13759 
13760  If Callon true then called to set an unrestricted call-on route - suppress messages
13761  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
13762  & ensure signal/buffers/continuation.
13763  Note that can't select ConsecSignalsRoute for non-preferred routes.
13764  Check if train on element & disallow.
13765  Set default values for retained parameters:-
13766  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
13767  StartSelectionRouteID = route that selection starts in if there is one;
13768 
13769  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
13770  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
13771  validity. This is just for safety reasons, the PrefDir values aren't used.
13772  StartElement1 & 2 are set to these PrefDirelements.
13773 
13774  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
13775 
13776  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
13777  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
13778  blank StartElement2 (only want to use the route element), then return true.
13779  Check if adjacent to start or end of an existing route & disallow if so.
13780  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
13781  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
13782  SetRemainingSearchVectorValues().
13783  Finally add the required element to the SearchVector & return true.
13784 */
13785  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
13786  AnsiString(VLoc) + "," + AnsiString((short)Callon));
13787  ClearRoute();
13788  int TrackVectorPosition;
13789  TTrackElement TrackElement;
13790  TPrefDirElement FirstElement, LastElement;
13791 
13792  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
13793  {
13794  Utilities->CallLogPop(258);
13795  return false;
13796  }
13797  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
13798  {
13799  if(!Callon)
13800  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
13801 // makes later adjacent route checks too complicated
13802  Utilities->CallLogPop(259);
13803  return false;
13804  }
13805 
13806  if(Track->IsLCAtHV(21, HLoc, VLoc))
13807  {
13808  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
13809  Utilities->CallLogPop(1910);
13810  return false;
13811  }
13812 
13813 // check if selected a train & disallow if so
13814  if(TrackElement.TrainIDOnElement > -1)
13815  {
13816  if(!Callon)
13817  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
13818  Utilities->CallLogPop(260);
13819  return false;
13820  }
13821 
13822 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
13823  TPrefDirElement PrefDirElement;
13824  int LockedVectorNumber;
13825 
13826  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
13827  {
13828  if(!Callon)
13829  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
13830  Utilities->CallLogPop(261);
13831  return false;
13832  }
13833  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
13834  {
13835  if(!Callon)
13836  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
13837  Utilities->CallLogPop(262);
13838  return false;
13839  }
13840 
13842 // AdjacentStartRouteNumber = -1;
13843  StartRoutePosition = TrackVectorPosition;
13844 // StartRouteSelectPosition = TrackVectorPosition;
13845 
13846  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
13847  TPrefDirElement PrefDirElement2(TrackElement);
13848 
13849  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
13850  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
13851  TPrefDirElement BlankElement;
13852 
13853  PrefDirElement1.ELinkPos = 0;
13854  PrefDirElement1.XLinkPos = 1;
13855  PrefDirElement1.ELink = PrefDirElement1.Link[0];
13856  PrefDirElement1.XLink = PrefDirElement1.Link[1];
13857  if(!(PrefDirElement1.EntryExitNumber()))
13858  {
13859  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
13860  // no need for bridge check as bridge selections not allowed
13861  }
13862  PrefDirElement1.CheckCount = 9;
13863  PrefDirElement2.ELinkPos = 1;
13864  PrefDirElement2.XLinkPos = 0;
13865  PrefDirElement2.ELink = PrefDirElement2.Link[1];
13866  PrefDirElement2.XLink = PrefDirElement2.Link[0];
13867  if(!(PrefDirElement2.EntryExitNumber()))
13868  {
13869  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
13870  }
13871  PrefDirElement2.CheckCount = 9; // both now set
13872 
13873 // set StartElements to the above PrefDirElements
13874  StartElement1 = PrefDirElement1;
13875  StartElement2 = PrefDirElement2;
13876 
13877 // no PrefDir check needed as doesn't need to be in a PrefDir
13878 
13879 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
13881  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13882 
13883  if(RoutePair.first > -1)
13884  {
13885  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
13886  {
13887  if(!Callon)
13888  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
13889  Utilities->CallLogPop(263);
13890  return false;
13891  }
13892  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
13893  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
13894  {
13895  if(!Callon)
13896  TrainController->StopTTClockMessage(39, "No forward connection from this position");
13897  Utilities->CallLogPop(264);
13898  return false;
13899  }
13900  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
13901  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
13902  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13903  {
13904  if(!Callon)
13905  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
13906  Utilities->CallLogPop(265);
13907  return false;
13908  }
13909  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
13911  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
13912  StartElement2 = BlankElement; // only use the route element
13914  Utilities->CallLogPop(266);
13915  return true; // all retained values set
13916  }
13917 
13918  else // selection not in an existing route
13919  {
13920 // check if it's adjacent to start of an an existing route,
13921  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13922  {
13923  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
13924  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
13925  {
13926  if(!Callon)
13927  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
13928  Utilities->CallLogPop(267);
13929  return false;
13930  }
13931  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
13932  {
13933  if(!Callon)
13934  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
13935  Utilities->CallLogPop(268);
13936  return false;
13937  }
13938  }
13939 // check if it's adjacent to end of an an existing route,
13940  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13941  {
13943  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
13944  {
13945  if(!Callon)
13946  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
13947  Utilities->CallLogPop(269);
13948  return false;
13949  }
13950  }
13951  // not in a route or adjacent to start or end of a route
13952  // in this case reset all variable values to -1 & CheckCount to 4
13953  StartElement1.ELink = -1;
13954  StartElement1.ELinkPos = -1;
13955  StartElement1.XLink = -1;
13956  StartElement1.XLinkPos = -1;
13957  StartElement1.EXNumber = -1;
13959  StartElement2 = BlankElement;
13960  SearchVector.push_back(StartElement1);
13961  Utilities->CallLogPop(270);
13962  return true;
13963  }
13964 }
13965 
13966 // ---------------------------------------------------------------------------
13967 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
13968 
13969 /*
13970  If Callon true then called to set an unrestricted call-on route - suppress messages & allow points to be selected
13971 
13972  Declare the following integers:-
13973  EndPosition - TrackVectorPosition for the selection;
13974  ReqPosRouteID - for the existing route selected, set to -1 if not used and initially;
13975  Check if selection is a valid track element and set EndPosition.
13976  Cancel if select original start element, then check that not points, bridge or crossover.
13977  Check & fail if a train is present at the selection.
13978  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
13979  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
13980  No check needed for selection in EveryPrefDir.
13981  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
13982  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
13983  as don't need it if in a route.
13984  Check if selection adj to start or end of a route and disallow.
13985  Fail if select same route as starting route, though should already have failed earlier if this is so.
13986 
13987  If there's a StartSelectionRouteID then StartElement1 will be set to
13988  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
13989  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
13990  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
13991  to add the new route to the AllRoutesVectorPtr.
13992  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
13993  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
13994  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
13995  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
13996  the search vector values and return.
13997  If not returned yet then have failed to find the required element so return false with no message.
13998 */
13999 
14000 {
14001 // get EndPosition
14002  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
14003  AnsiString(VLoc));
14004  int EndPosition;
14005 
14006  TotalSearchCount = 0;
14007  ReqPosRouteID = IDInt(-1); // for not used
14008  TTrackElement TrackElement;
14009  TPrefDirElement BlankElement;
14010 
14011  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14012  {
14013  Utilities->CallLogPop(271);
14014  return false;
14015  }
14016 // EndPosition = EndSelectPosition;
14017 // cancel selection if on original start element
14018  if(EndPosition == StartRoutePosition)
14019  {
14020  Utilities->CallLogPop(272);
14021  return false;
14022  }
14023 
14024  if(Track->IsLCAtHV(22, HLoc, VLoc))
14025  {
14026  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
14027  Utilities->CallLogPop(1911);
14028  return false;
14029  }
14030 
14031  if((TrackElement.TrackType == Points) && !Callon)
14032  {
14033  if(!Callon)
14034  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
14035 // makes later adjacent route checks too complicated
14036  Utilities->CallLogPop(273);
14037  return false;
14038  }
14039 
14040  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
14041  {
14042  if(!Callon)
14043  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
14044 // makes later adjacent route checks too complicated
14045  Utilities->CallLogPop(1861);
14046  return false;
14047  }
14048 
14049 // check if train on element
14050  if(TrackElement.TrainIDOnElement > -1)
14051  {
14052  if(!Callon)
14053  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
14054  Utilities->CallLogPop(274);
14055  return false;
14056  }
14057 
14058 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
14059 // check passed)
14060  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
14061  TPrefDirElement EndElement2(TrackElement);
14062 
14063  EndElement1.TrackVectorPosition = EndPosition;
14064  EndElement2.TrackVectorPosition = EndPosition;
14065  EndElement1.ELinkPos = 0;
14066  EndElement1.XLinkPos = 1;
14067  EndElement1.ELink = EndElement1.Link[0];
14068  EndElement1.XLink = EndElement1.Link[1];
14069  if(!(EndElement1.EntryExitNumber()))
14070  {
14071  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
14072  }
14073  EndElement1.CheckCount = 9;
14074  EndElement2.ELinkPos = 1;
14075  EndElement2.XLinkPos = 0;
14076  EndElement2.ELink = EndElement2.Link[1];
14077  EndElement2.XLink = EndElement2.Link[0];
14078  if(!(EndElement2.EntryExitNumber()))
14079  {
14080  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
14081  }
14082  EndElement2.CheckCount = 9; // both now set
14083 
14084 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14085 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14086 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14087 
14088  if(EndElement1.HLoc >= StartElement1.HLoc)
14089  {
14091  SearchLimitHighH = EndElement1.HLoc + 15;
14092  }
14093  else
14094  {
14095  SearchLimitLowH = EndElement1.HLoc - 15;
14097  }
14098 
14099  if(EndElement1.VLoc >= StartElement1.VLoc)
14100  {
14102  SearchLimitHighV = EndElement1.VLoc + 15;
14103  }
14104  else
14105  {
14106  SearchLimitLowV = EndElement1.VLoc - 15;
14108  }
14109 
14110 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14111  check & TotalSearchCounts check
14112  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14113  {
14114  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
14115  Utilities->CallLogPop(1694);
14116  return false;
14117  }
14118 */
14119 // don't need EveryPrefDir check for NonPreferredRoute
14120 
14121 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
14122 // bool InRoute = false;
14124  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14125 
14126  if(RoutePair.first > -1)
14127  {
14128  if(RoutePair.second != 0) // not first element in existing route so no good
14129  {
14130  if(!Callon)
14131  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
14132  Utilities->CallLogPop(275);
14133  return false;
14134  }
14135  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
14136 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14137  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
14138  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14139  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14140  {
14141  if(!Callon)
14142  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
14143  Utilities->CallLogPop(276);
14144  return false;
14145  }
14146  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
14147  EndElement2 = BlankElement; // only need the route element
14148  EndPosition = EndElement1.TrackVectorPosition;
14149  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
14150  }
14151 
14152 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
14153  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14154  {
14155  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
14156  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
14157 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14158 // && (AdjPosition != StartRoutePosition))
14159  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14160  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14161  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
14162  {
14163  if(!Callon)
14164  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
14165  Utilities->CallLogPop(277);
14166  return false;
14167  }
14168 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14169 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
14170  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14171  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14172  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
14173  (AdjPosition != StartRoutePosition))
14174  {
14175  if(!Callon)
14176  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
14177  Utilities->CallLogPop(278);
14178  return false;
14179  }
14180 
14181 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
14183  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
14184  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
14185  {
14186  if(!Callon)
14187  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
14188  Utilities->CallLogPop(279);
14189  return false;
14190  }
14191  }
14192 
14193 // check for same route as start element
14195  {
14196  if(!Callon)
14197  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
14198  Utilities->CallLogPop(280);
14199  return false;
14200  }
14201 
14202 // check for a looping route
14203  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14204  {
14206  {
14207  if(!Callon)
14208  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
14209  Utilities->CallLogPop(1845);
14210  return false;
14211  }
14212  }
14213 
14214 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14215 // so search from this element.
14216 
14217  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
14218 
14219  if(StartSelectionRouteID > -1)
14220  {
14221  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
14222  {
14224  if(PointsToBeChanged(0))
14225  {
14226  PointsChanged = true;
14227  }
14228  Utilities->CallLogPop(281);
14229  return true;
14230  }
14231  else
14232  {
14233  if(!Callon)
14235  Utilities->CallLogPop(282);
14236  return false;
14237  }
14238  }
14239  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
14240  // search on the 2 ways out of the element, which has to be a 2-ended element
14241  {
14242 // check if selection adjacent to start element and if so use that
14243  if(SearchVector.at(0).Conn[0] == EndPosition)
14244  {
14245  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
14246  {
14248  if(PointsToBeChanged(1))
14249  {
14250  PointsChanged = true;
14251  }
14252  Utilities->CallLogPop(283);
14253  return true;
14254  }
14255  else
14256  {
14257  if(!Callon)
14259  Utilities->CallLogPop(284);
14260  return false;
14261  }
14262  }
14263  else if(SearchVector.at(0).Conn[1] == EndPosition)
14264  {
14265  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
14266  {
14268  if(PointsToBeChanged(2))
14269  {
14270  PointsChanged = true;
14271  }
14272  Utilities->CallLogPop(285);
14273  return true;
14274  }
14275  else
14276  {
14277  if(!Callon)
14279  Utilities->CallLogPop(286);
14280  return false;
14281  }
14282  }
14283  // now start off in the best direction
14284  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
14285 
14286  if(SearchVector.at(0).Config[BestPos] != End)
14287  {
14288  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14289  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
14290  {
14292  if(PointsToBeChanged(3))
14293  {
14294  PointsChanged = true;
14295  }
14296  Utilities->CallLogPop(287);
14297  return true;
14298  }
14299  }
14300  if(SearchVector.at(0).Config[1 - BestPos] != End)
14301  {
14302  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14303  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
14304  {
14306  if(PointsToBeChanged(4))
14307  {
14308  PointsChanged = true;
14309  }
14310  Utilities->CallLogPop(288);
14311  return true;
14312  }
14313  }
14314  }
14315  if(!Callon)
14317  Utilities->CallLogPop(289);
14318  return false;
14319 }
14320 
14321 // ---------------------------------------------------------------------------
14322 
14323 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
14324 /*
14325  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
14326  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
14327  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
14328  Keep a count of entries in SearchVector during the current function call, so that this number can be
14329  erased for an unproductive branch search.
14330  First check (within the loop) whether XLink leads to an End & return false if so.
14331  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
14332  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14333  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
14334  train on element (unless a bridge & train on different track), or if element
14335  fouls an existing diagonal route (except if element is a leading point - these checked later).
14336  Then check if found required element. If so save it & return true.
14337  If not the required element check if buffer or continuation, & if so erase all searchvector
14338  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
14339  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
14340  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
14341  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
14342  When return true have 8 items from CheckCount established, only waiting for EXNumber
14343 */
14344 {
14345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
14346  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
14347  int VectorCount = 0;
14348 
14349 // check for a fouled diagonal for first element. Added for v1.3.2
14350  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
14351  (CurrentTrackElement.Link[XLinkPos] == 9))
14352  {
14353  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
14354  {
14355  for(int x = 0; x < VectorCount; x++)
14356  SearchVector.erase(SearchVector.end() - 1);
14357  Utilities->CallLogPop(2044);
14358  return false;
14359  }
14360  }
14361 
14362  while(true)
14363  {
14364  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
14365  {
14366  for(int x = 0; x < VectorCount; x++)
14367  SearchVector.erase(SearchVector.end() - 1);
14368  Utilities->CallLogPop(1927);
14369  return false;
14370  }
14371  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
14372  {
14373  for(int x = 0; x < VectorCount; x++)
14374  SearchVector.erase(SearchVector.end() - 1);
14375  Utilities->CallLogPop(290);
14376  return false;
14377  }
14378  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
14379  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
14380  TPrefDirElement SearchElement(NextTrackElement);
14381  SearchElement.TrackVectorPosition = NextPosition;
14382  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
14383  SearchElement.ELinkPos = NextELinkPos;
14384  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
14385  int NextXLinkPos;
14386  if(SearchElement.ELinkPos == 0)
14387  NextXLinkPos = 1;
14388  if(SearchElement.ELinkPos == 1)
14389  NextXLinkPos = 0;
14390  if(SearchElement.ELinkPos == 2)
14391  NextXLinkPos = 3;
14392  if(SearchElement.ELinkPos == 3)
14393  NextXLinkPos = 2;
14394  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14395  {
14396  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14397  // but may be buffers, continuation or gap
14398  SearchElement.XLinkPos = NextXLinkPos;
14399  }
14400 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
14401 // can't set XLink or XLinkPos yet if the element is a leading point.
14402 
14403 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14404  for(unsigned int x = 0; x < SearchVector.size(); x++)
14405  {
14406  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14407  {
14408  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14409  // OK if it's a bridge & routes on different tracks
14410  {
14411  for(int x = 0; x < VectorCount; x++)
14412  SearchVector.erase(SearchVector.end() - 1);
14413  Utilities->CallLogPop(291);
14414  return false;
14415  }
14416  }
14417  }
14418 
14419 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14420  TAllRoutes::TRouteElementPair SecondPair;
14422  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14423  if(RoutePair.first > -1)
14424  {
14425  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14426  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
14427  RoutePair.second).ELinkPos)))
14428  {
14429  // still OK if start of an expected route
14430  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
14431  {
14432  for(int x = 0; x < VectorCount; x++)
14433  SearchVector.erase(SearchVector.end() - 1);
14434  Utilities->CallLogPop(292);
14435  return false; // only allow for start of an expected route
14436  }
14437  }
14438  }
14439  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14440  {
14441  // OK if it's a bridge & routes on different tracks
14442  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
14443  SecondPair.second).ELinkPos)))
14444  {
14445  // still OK if start of an expected route
14446  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
14447  {
14448  for(int x = 0; x < VectorCount; x++)
14449  SearchVector.erase(SearchVector.end() - 1);
14450  Utilities->CallLogPop(293);
14451  return false; // only allow for start of an expected route
14452  }
14453  }
14454  }
14455 
14456 // check if a train on element, unless a bridge & train on different track
14457 // OK of same train as start element - no, drop this
14458 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14459  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14460  {
14461  for(int x = 0; x < VectorCount; x++)
14462  SearchVector.erase(SearchVector.end() - 1);
14463  Utilities->CallLogPop(294);
14464  return false;
14465  }
14466  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14467  {
14468  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14469  {
14470  for(int x = 0; x < VectorCount; x++)
14471  SearchVector.erase(SearchVector.end() - 1);
14472  Utilities->CallLogPop(295);
14473  return false;
14474  }
14475  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14476  {
14477  for(int x = 0; x < VectorCount; x++)
14478  SearchVector.erase(SearchVector.end() - 1);
14479  Utilities->CallLogPop(296);
14480  return false;
14481  }
14482  }
14483 
14484 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
14485  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14486  {
14487  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14488  {
14489  for(int x = 0; x < VectorCount; x++)
14490  SearchVector.erase(SearchVector.end() - 1);
14491  Utilities->CallLogPop(297);
14492  return false;
14493  }
14494  }
14495 
14496 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
14497 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
14498 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
14500  {
14501  for(int x = 0; x < VectorCount; x++)
14502  SearchVector.erase(SearchVector.end() - 1);
14503  Utilities->CallLogPop(1689);
14504  return false;
14505  }
14506 
14507 // check if found it
14508  if(SearchElement.TrackVectorPosition == RequiredPosition)
14509  {
14510  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
14511  {
14512  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
14513  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
14514  else
14515  SearchElement.XLinkPos = 1;
14516 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
14517  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
14518  }
14519  SearchVector.push_back(SearchElement);
14520  VectorCount++; // not really needed but include for tidyness
14521  TotalSearchCount++;
14522  Utilities->CallLogPop(298);
14523  return true;
14524  }
14525 // Not the required element - check if a buffer or continuation
14526  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
14527  {
14528  for(int x = 0; x < VectorCount; x++)
14529  SearchVector.erase(SearchVector.end() - 1);
14530  Utilities->CallLogPop(299);
14531  return false;
14532  }
14533 
14534 // check if SearchVector exceeds a size of 150
14535  if(SearchVector.size() > 150)
14536  {
14537  for(int x = 0; x < VectorCount; x++)
14538  SearchVector.erase(SearchVector.end() - 1);
14539  Utilities->CallLogPop(1421);
14540  return false;
14541  }
14542 
14543 // check if reached a leading point
14544  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
14545  {
14546 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
14547  int SearchPos1 = SearchElement.Attribute + 1;
14548  int SearchPos2;
14549  if(SearchPos1 == 2)
14550  SearchPos1++;
14551  if(SearchPos1 == 1)
14552  SearchPos2 = 3;
14553  else
14554  SearchPos2 = 1;
14555 // push element with XLink set to position [SearchPos1]
14556  SearchElement.XLink = SearchElement.Link[SearchPos1];
14557  SearchElement.XLinkPos = SearchPos1;
14558 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
14559  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14560  {
14561  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14562  {
14563  for(int x = 0; x < VectorCount; x++)
14564  SearchVector.erase(SearchVector.end() - 1);
14565  Utilities->CallLogPop(300);
14566  return false;
14567  }
14568  }
14569  SearchVector.push_back(SearchElement);
14570  VectorCount++;
14571  TotalSearchCount++;
14572 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
14573 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
14574 // recursive search as has to be a TTrackElement for non-preferred route searches
14575  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
14576  {
14577  Utilities->CallLogPop(301);
14578  return true;
14579  }
14580  else
14581  {
14582 // remove leading point with XLinkPos [SearchPos1]
14583  SearchVector.erase(SearchVector.end() - 1);
14584  VectorCount--;
14585 // push element with XLink set to position [SearchPos2]
14586  SearchElement.XLink = SearchElement.Link[SearchPos2];
14587  SearchElement.XLinkPos = SearchPos2;
14588 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
14589  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14590  {
14591  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14592  {
14593  for(int x = 0; x < VectorCount; x++)
14594  SearchVector.erase(SearchVector.end() - 1);
14595  Utilities->CallLogPop(302);
14596  return false;
14597  }
14598  }
14599  SearchVector.push_back(SearchElement);
14600  VectorCount++;
14601  TotalSearchCount++;
14602 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
14603  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
14604  {
14605  Utilities->CallLogPop(303);
14606  return true;
14607  }
14608  else
14609  {
14610  for(int x = 0; x < VectorCount; x++)
14611  SearchVector.erase(SearchVector.end() - 1);
14612  Utilities->CallLogPop(304);
14613  return false;
14614  }
14615  }
14616  } // if leading point
14617 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
14618 // ready for next element on route
14619  SearchVector.push_back(SearchElement);
14620  VectorCount++;
14621  TotalSearchCount++;
14622  CurrentTrackElement = SearchElement;
14623  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
14624  } // while(true)
14625 }
14626 
14627 // ---------------------------------------------------------------------------
14628 
14630 
14631 /*
14632  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
14633  having all values set (since not necessarily on PrefDirs).
14634  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
14635  (if it was the start), so these are checked first and set if necessary. All elements now have
14636  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
14637  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
14638  to set the route colour and direction graphics.
14639 */
14640 
14641 {
14642  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
14643  if(SearchVector.size() == 0)
14644  {
14645  throw Exception("Error, SearchVector empty");
14646  }
14647 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
14648 // hence need to examine and update it if necessary
14649  TPrefDirElement SecondElement;
14650 
14651  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
14652  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
14653  // need above check or SecondElement will fail
14654  {
14655  SecondElement = SearchVector.at(1);
14656  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
14657  for(int x = 0; x < 4; x++)
14658  {
14659  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
14660  {
14661  if(SearchVector.at(0).XLink == -1) // i.e. not set
14662  {
14663  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
14664  SearchVector.at(0).XLinkPos = x;
14665  }
14666  int ELinkPos;
14667  if(SearchVector.at(0).XLinkPos == 0)
14668  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
14669  // linked to 1st searchvector element, & if XLink was set then x may not correspond
14670  if(SearchVector.at(0).XLinkPos == 1)
14671  ELinkPos = 0;
14672  if(SearchVector.at(0).XLinkPos == 2)
14673  ELinkPos = 3;
14674  if(SearchVector.at(0).XLinkPos == 3)
14675  ELinkPos = 2;
14676  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
14677  {
14678  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
14679  SearchVector.at(0).ELinkPos = ELinkPos;
14680  }
14681  break; // no point going any further
14682  }
14683  }
14684  }
14685  for(unsigned int x = 0; x < SearchVector.size(); x++)
14686  {
14687  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
14688 // set EXNumber
14689  if(!(SearchVector.at(x).EntryExitNumber()))
14690  {
14691  throw Exception("Error in EntryExitNumber 3");
14692  }
14693  SearchVector.at(x).CheckCount++;
14694 // all values now incorporated
14695  }
14696 
14697  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
14698 // This function is only called here for nonsignals routes, so AutoSigsFlag & ConsecSignalsRoute both false
14699 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
14700  Utilities->CallLogPop(305);
14701 }
14702 
14703 // ---------------------------------------------------------------------------
14704 
14706 
14707 /*
14708  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
14709  AutoSigsRoute.
14710  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
14711  beginning or the end.
14712  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
14713  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
14714  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
14715  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
14716  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
14717  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
14718  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
14719 
14720  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
14721  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
14722  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
14723  route at the start.
14724 
14725  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
14726  for the new route and return.
14727 */
14728 
14729 {
14730  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
14731  AnsiString(ReqPosRouteID.GetInt()));
14732  if(SearchVector.size() < 1)
14733  {
14734  Utilities->CallLogPop(306);
14735  return;
14736  }
14737  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
14738  if(!ValidatePrefDir(6))
14739  {
14740  Utilities->CallLogPop(307);
14741  return;
14742  }
14743 
14744  TAllRoutes::TLockedRouteClass LockedRouteObject;
14745 
14747  unsigned int TruncatePrefDirPosition = 0;
14748 
14749  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
14750 /* if have ReqPosRouteID:
14751  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
14752  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14753  then enter the new route into the AllRoutesVector
14754 */
14755  {
14757  {
14758  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
14759  x++) // start at 1 as first element already in SearchVector
14760  {
14762  }
14763  // note that route numbers in map adjusted when ReqPos route cleared
14765  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
14766  // set during ClearRouteDuringRouteBuildingAt)
14768  {
14771  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
14772  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
14773  }
14774  }
14776  {
14777  SearchVector.pop_back();
14778  }
14779  }
14780 
14781  if(StartSelectionRouteID > -1)
14782 /* if have StartSelectionRouteID:
14783  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
14784  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
14785 */
14786  {
14788  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
14789  {
14791  {
14792  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
14793  for(unsigned int x = 0; x < SearchVector.size(); x++)
14794  {
14796  RouteNumber, GetFixedSearchElementAt(7, x));
14797  // find & store locked route truncate position in PrefDirVector for later use
14799  {
14800  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
14801  {
14802  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
14803  }
14804  }
14805  }
14807  {
14808  throw Exception("Failed to validate extended route for nonpreferred route");
14809  }
14812  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // ConsecSignalsRoute is false
14813  // now add the reinstated locked route if required and set signals accordingly
14814  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
14815  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
14816  // that I haven't thought of
14818  {
14819  LockedRouteObject.RouteNumber = RouteNumber;
14820  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
14821  // now reset the signals for the locked route
14822  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
14823  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
14824  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
14825  // return all signals to red in route section to be truncated
14826  {
14827  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
14828  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
14829  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
14830  {
14831  TrackElement.Attribute = 0;
14832  Track->PlotSignal(11, TrackElement, Display);
14833  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
14834  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
14835  }
14836  }
14837  }
14838  AllRoutes->CheckMapAndRoutes(3); // test
14839  Utilities->CallLogPop(308);
14840  return;
14841  }
14842  }
14843  else
14844  {
14846  }
14847 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
14848 // hence nothing to do here
14849  }
14850 
14851  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
14852  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
14853  {
14854  throw Exception("Failed to validate single route for nonpreferred route");
14855  }
14856  AllRoutes->StoreOneRoute(2, this);
14857  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
14858  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
14859  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
14860  AllRoutes->CheckMapAndRoutes(4); // test
14861  Utilities->CallLogPop(309);
14862 }
14863 
14864 // ---------------------------------------------------------------------------
14865 
14866 void TOneRoute::SetRoutePoints(int Caller) const
14867 /*
14868  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
14869  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
14870  when they were created.
14871 */
14872 {
14873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
14874  if(!PrefDirVector.empty())
14875  {
14876  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
14877  {
14878  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
14879  {
14880  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
14881  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
14882  }
14883  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
14884  {
14885  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
14886  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
14887  }
14888  }
14889  }
14890  Utilities->CallLogPop(327);
14891 }
14892 
14893 // ---------------------------------------------------------------------------
14894 
14895 void TOneRoute::SetRouteSignals(int Caller) const
14896 /* Used for new train additions in AddTrain and in route setting
14897  Set the signals as follows:-
14898  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
14899  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
14900  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
14901  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
14902  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
14903  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
14904  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
14905  of the foregoing are found but there is a further forward linked forward route then the function returns false with
14906  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
14907 
14908  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
14909  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
14910  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
14911  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
14912  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
14913  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
14914  as a green signal.
14915 */
14916 {
14917  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
14918  if(!PrefDirVector.empty())
14919  {
14920  // get target Attribute value, check first if there is a forward linked route
14921  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
14922  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
14923  int ForwardLinkedRouteNumber, Attribute = 0;
14924  if(LastElement.Conn[LastElement.XLinkPos] > -1)
14925  // Note that LastElement can't be points but can be linked to points
14926  {
14927  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
14928  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
14929  {
14930  if(ForwardLinkedRouteNumber > -1)
14931  {
14932  int NextForwardLinkedRouteNumber = -1;
14933  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
14934  Attribute)))
14935  {
14936  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
14937  }
14938  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
14939  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
14940  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
14941  }
14942  }
14943  }
14944  int RouteNumber;
14945  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
14946  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
14947  if(RouteType != TAllRoutes::NoRoute)
14948  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
14949  {
14950  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
14951  }
14952  }
14953  Utilities->CallLogPop(1720);
14954 }
14955 
14956 // ---------------------------------------------------------------------------
14957 
14958 bool TOneRoute::PointsToBeChanged(int Caller) const
14959 { // true if at any point in SearchVector points have to be changed
14960  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
14961  if(!SearchVector.empty())
14962  {
14963  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
14964  {
14965  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
14966  {
14967  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
14968  {
14969  Utilities->CallLogPop(1717);
14970  return true;
14971  }
14972  }
14973  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
14974  {
14975  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
14976  {
14977  Utilities->CallLogPop(1718);
14978  return true;
14979  }
14980  }
14981  }
14982  }
14983  Utilities->CallLogPop(1719);
14984  return false;
14985 }
14986 
14987 // ---------------------------------------------------------------------------
14988 
14989 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
14990 /*
14991  Works forward through the route until finds:-
14992  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
14993  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
14994  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
14995  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
14996  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
14997  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
14998  returns true;
14999  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
15000 */
15001 {
15002  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
15003  Attribute = 0;
15004  NextForwardLinkedRouteNumber = -1;
15005  for(unsigned int x = 0; x < PrefDirSize(); x++)
15006  {
15007  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
15008  if(PrefDirVector.at(x).TrackType == Bridge)
15009  {
15010  if(PrefDirVector.at(x).XLinkPos < 2)
15011  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15012  else
15013  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15014  }
15015  if(TrainID != -1)
15016  {
15017  Utilities->CallLogPop(328);
15018  return true;
15019  }
15020  if(PrefDirVector.at(x).TrackType == Buffers)
15021  {
15022  Attribute = 1;
15023  Utilities->CallLogPop(329);
15024  return true;
15025  }
15026  if(PrefDirVector.at(x).TrackType == Continuation)
15027  {
15028  Attribute = 3;
15029  Utilities->CallLogPop(330);
15030  return true;
15031  }
15032  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15033  {
15034  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15035  {
15036  Attribute = 0;
15037  Utilities->CallLogPop(1950);
15038  return true;
15039  }
15040  }
15041  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
15042  {
15043  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
15044  if(Attribute > 3)
15045  Attribute = 3;
15046  Utilities->CallLogPop(331);
15047  return true;
15048  }
15049  if(x == PrefDirSize() - 1)
15050  {
15051  TPrefDirElement LastElement = PrefDirVector.at(x);
15052  if(LastElement.Conn[LastElement.XLinkPos] > -1)
15053  {
15054  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
15055  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
15056  {
15057  Attribute = 0;
15058  Utilities->CallLogPop(332);
15059  return false;
15060  }
15061  }
15062  }
15063  }
15064  Utilities->CallLogPop(333);
15065  return true;
15066 }
15067 
15068 // ---------------------------------------------------------------------------
15069 
15070 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
15071 /*
15072  This function is only called by TAllRoutes::SetAllRearwardsSignals.
15073 
15074  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
15075  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
15076  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
15077  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
15078  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
15079  a route.
15080 
15081  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
15082  signal. If find a signal (but see note below) set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
15083  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3. On completion Attribute is
15084  passed back from the function as a reference. If no train is found before the beginning of the route is reached the function returns true.
15085 
15086  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
15087  and the next rearwards signal becomes yellow, although it's the first in the route
15088 */
15089 {
15090  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
15091  AnsiString(PrefDirVectorStartPosition));
15092  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
15093  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
15094 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
15095 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
15096  bool SkipContinuationAndBufferAttributeChange = false;
15097 
15098  if(!PrefDirVector.empty())
15099  {
15100  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
15101  {
15102  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15103  if(PrefDirPtr->TrackType == Bridge)
15104  {
15105  if(PrefDirPtr->XLinkPos < 2)
15106  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15107  else
15108  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15109  }
15110  if(TrainID != -1)
15111  {
15112  SkipContinuationAndBufferAttributeChange = true;
15113  break;
15114  }
15115  }
15116 
15119  {
15120  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
15121  AutoSigVectorIT++)
15122  {
15123  if(!AllRoutes->AllRoutesVector.empty())
15124  {
15125  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
15126  {
15127  SkipContinuationAndBufferAttributeChange = true;
15128  break;
15129  }
15130  }
15131  }
15132  }
15133 
15135  SkipContinuationAndBufferAttributeChange = true;
15136 
15137  if(!SkipContinuationAndBufferAttributeChange)
15138  {
15139  if(PrefDirVector.back().TrackType == Buffers)
15140  Attribute = 1; // treat buffer as red signal
15141  if(PrefDirVector.back().TrackType == Continuation)
15142  Attribute = 3; // treat continuation as a green signal
15143  }
15144 
15145  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15146  {
15147  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15148  if(PrefDirPtr->TrackType == Bridge)
15149  {
15150  if(PrefDirPtr->XLinkPos < 2)
15151  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15152  else
15153  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15154  }
15155  if(TrainID != -1)
15156  {
15157  Utilities->CallLogPop(334);
15158  return false;
15159  }
15160  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
15161  // the attribute to 0 so first signal behind the LC is red
15162  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15163  {
15164  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15165  {
15166  Attribute = 0;
15167  }
15168  }
15169 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
15170 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
15171  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
15172  {
15173  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
15174  PrefDirPtr->ConsecSignals)
15175  {
15176  if(Attribute < 3)
15177  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
15178  else
15179  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
15180  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
15181  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
15182  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
15183  {
15184  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15185  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
15186  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15187  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
15188  }
15189  if(Attribute < 3)
15190  Attribute++;
15191  Display->Update(); // update after recent plots
15192  }
15193  }
15194  }
15195  }
15196  Utilities->CallLogPop(335);
15197  return true;
15198 }
15199 
15200 // ---------------------------------------------------------------------------
15201 
15202 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
15203 /*
15204  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
15205  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
15206  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
15207  Selection invalid if a train at or before the truncate point; select a bridge; trying to leave a single element; last element to be left
15208  not a signal (for ConsecSignalsRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
15209  ConsecSignalsRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
15210  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
15211  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
15212 */
15213 {
15214  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
15215  "," + AnsiString((short)ConsecSignalsRoute));
15216  bool ElementInRoute = false;
15217  bool TrainOccupyingRoute = false;
15218 
15219  for(unsigned int b = 0; b < PrefDirSize(); b++)
15220  {
15221  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15222  {
15223  ElementInRoute = true;
15224  break;
15225  }
15226  }
15227  if(!ElementInRoute)
15228  {
15229  ReturnFlag = NotInRoute;
15230  Utilities->CallLogPop(336);
15231  return;
15232  }
15233 // it is in the route so continue, first look for a train or a flashing level crossing
15234  for(int b = PrefDirSize() - 1; b >= 0; b--)
15235  {
15236  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
15237  if(PrefDirVector.at(b).TrackType == Bridge)
15238  {
15239  if(PrefDirVector.at(b).XLinkPos < 2)
15240  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15241  else
15242  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15243  }
15244  if(TrainID != -1)
15245  {
15246 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
15247 // ReturnFlag = InRouteFalse;
15248 // Utilities->CallLogPop(337);
15249 // return;
15250 // above removed at v2.1.0 so that routes can be locked when occupied, below added
15251  TrainOccupyingRoute = true; // train is forward of the truncate point
15252  }
15253  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
15254  {
15255  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
15256  ReturnFlag = InRouteFalse;
15257  Utilities->CallLogPop(1941);
15258  return;
15259  }
15260  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15261  {
15262  break; // OK found truncate element & no flashing LC in front
15263  }
15264  }
15265 
15266  for(unsigned int b = 0; b < PrefDirSize(); b++)
15267  {
15268  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
15269  {
15270  if(PrefDirVector.at(b).TrackType == Bridge)
15271  {
15272  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
15273  ReturnFlag = InRouteFalse;
15274  Utilities->CallLogPop(338);
15275  return;
15276  }
15277  if(b == 1)
15278  {
15279  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
15280  ReturnFlag = InRouteFalse;
15281  Utilities->CallLogPop(339);
15282  return;
15283  }
15284  if(b > 0)
15285  {
15286  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
15287  if(TempElement.ConsecSignals || TempElement.AutoSignals)
15288  {
15289  if(TempElement.Config[TempElement.XLinkPos] != Signal)
15290  {
15291  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
15292  ReturnFlag = InRouteFalse;
15293  Utilities->CallLogPop(340);
15294  return;
15295  }
15296  }
15297  else
15298  {
15299  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
15300  {
15301  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
15302  ReturnFlag = InRouteFalse;
15303  Utilities->CallLogPop(341);
15304  return;
15305  }
15306  }
15307  }
15308 
15309  int RouteNumber;
15311 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
15312 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
15313 
15314 // check if part of this route already locked & disallow if so
15315  if(!(AllRoutes->LockedRouteVector.empty()))
15316  {
15318  {
15319  if(LRVIT->RouteNumber == RouteNumber)
15320  {
15321  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
15322  ReturnFlag = InRouteFalse;
15323  Utilities->CallLogPop(749);
15324  return;
15325  }
15326  }
15327  }
15328 
15329  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
15330  // RouteLockingRequired only checks for trains approaching
15331  {
15334  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
15335  L"Warning!", MB_YESNO | MB_ICONWARNING);
15336  TrainController->BaseTime = TDateTime::CurrentDateTime();
15338  if(button == IDNO)
15339  {
15340  ReturnFlag = InRouteTrue; // still return true even though don't act on it
15341  Utilities->CallLogPop(342);
15342  return;
15343  }
15344  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
15345  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
15346  TAllRoutes::TLockedRouteClass LockedRoute;
15347  bool ExistingLockedRouteModified = false;
15348  LockedRoute.RouteNumber = RouteNumber;
15349  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
15350  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
15351  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
15352  LockedRoute.LockStartTime = TrainController->TTClockTime;
15353 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
15354 // to use the new TruncateTrackVectorPosition & LockStartTime
15355  if(!AllRoutes->LockedRouteVector.empty())
15356  {
15357  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
15358  LRVIT++)
15359  {
15360  if(LRVIT->RouteNumber == RouteNumber)
15361  {
15362  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
15363  LRVIT->LockStartTime = LockedRoute.LockStartTime;
15364  ExistingLockedRouteModified = true;
15365  }
15366  }
15367  }
15368  if(!ExistingLockedRouteModified)
15369  AllRoutes->LockedRouteVector.push_back(LockedRoute);
15370  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
15371  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15372  // return all signals to red in route section to be truncated
15373  {
15374  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
15375  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
15376  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15377  {
15378  TrackElement.Attribute = 0;
15379  Track->PlotSignal(2, TrackElement, Display);
15380  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15381  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15382  }
15383  }
15384 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
15385  ReturnFlag = InRouteTrue;
15386  }
15387  else
15388  {
15389  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
15390  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15391  {
15392  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
15393  ReturnFlag = InRouteTrue;
15394  }
15395  }
15396  AllRoutes->CheckMapAndRoutes(5); // test
15397  Utilities->CallLogPop(343);
15398  return;
15399  }
15400  }
15401  ReturnFlag = NotInRoute;
15402  Utilities->CallLogPop(344);
15403 }
15404 
15405 // ---------------------------------------------------------------------------
15407 /*
15408  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
15409  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
15410  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
15411  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
15412  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
15413  the route colours.
15414 */
15415 {
15416  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
15417  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
15419  int RouteNumber;
15420  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
15421  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
15422 
15423  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
15424  {
15425  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
15426  {
15427  if(PrefDirVector.at(x).TrackType == SignalPost)
15428  {
15429  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
15430  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
15431  }
15432  }
15433  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
15434 // already set all signals to red in route so start at start of route for further rearwards signal setting
15435  }
15436  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
15437  {
15438  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
15439  }
15440  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
15441  AllRoutes->CheckMapAndRoutes(9); // test
15442  TrainController->BaseTime = TDateTime::CurrentDateTime();
15444  Utilities->CallLogPop(345);
15445  return;
15446 }
15447 
15448 // ---------------------------------------------------------------------------
15449 
15450 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
15451 /*
15452  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
15453 */
15454 {
15455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
15456  AnsiString((short)ConsecSignalsRoute));
15457  if(SearchVector.empty())
15458  {
15459  Utilities->CallLogPop(1149);
15460  return;
15461  }
15462  for(unsigned int b = 0; b < SearchVector.size(); b++)
15463  {
15464  GetModifiableSearchElementAt(1, b).EXGraphicPtr = GetModifiableSearchElementAt(2, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
15466  ConsecSignalsRoute);
15467  }
15468  Utilities->CallLogPop(346);
15469 }
15470 
15471 // ---------------------------------------------------------------------------
15472 
15473 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
15474 /*
15475  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
15476  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
15477  TOneRoute.
15478 */
15479 {
15480  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
15481  AnsiString((short)ConsecSignalsRoute));
15482  RouteFlash.RouteFlashVector.clear();
15483  TRouteFlashElement RouteFlashElement;
15484 
15485  for(unsigned int b = 0; b < SearchVector.size(); b++)
15486  {
15487  int H = GetFixedSearchElementAt(11, b).HLoc;
15488  int V = GetFixedSearchElementAt(12, b).VLoc;
15490  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
15491  RouteFlashElement.HLoc = H;
15492  RouteFlashElement.VLoc = V;
15494  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
15495  }
15496  Utilities->CallLogPop(348);
15497 }
15498 
15499 // ---------------------------------------------------------------------------
15500 
15501 void TOneRoute::SetLCChangeValues(int Caller, bool ConsecSignalsRoute)
15502 {
15503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)ConsecSignalsRoute));
15504  if(!PrefDirVector.empty())
15505  {
15506  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15507  {
15508  int H = PrefDirPtr->HLoc;
15509  int V = PrefDirPtr->VLoc;
15510  // check for any LCs that are closed to trains & set the flash values and store in the vector
15511  if(Track->IsLCAtHV(39, H, V))
15512  {
15513  if(Track->IsLCBarrierUpAtHV(0, H, V))
15514  {
15515  Track->LCChangeFlag = true;
15516  TTrack::TActiveLevelCrossing CLC; // constructor sets TrainPassed to false
15517  CLC.HLoc = H;
15518  CLC.VLoc = V;
15520  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
15523  CLC.ConsecSignals = ConsecSignalsRoute;
15524  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
15525  Track->ChangingLCVector.push_back(CLC);
15526  }
15527  }
15528  }
15529  }
15530  Utilities->CallLogPop(1948);
15531 }
15532 
15533 // ---------------------------------------------------------------------------
15534 
15536 /*
15537  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
15538  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
15539  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
15540  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
15541 */
15542 {
15543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
15544  if(!OverlayPlotted)
15545  {
15546  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
15547  {
15548  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
15549  continue;
15550  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
15551  Display->Update();
15552  }
15553  OverlayPlotted = true;
15554  }
15555  Utilities->CallLogPop(349);
15556 }
15557 
15558 // ---------------------------------------------------------------------------
15559 
15561 /*
15562  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
15563  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
15564  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
15565  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
15566 */
15567 {
15568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
15569  if(OverlayPlotted)
15570  {
15571  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
15572  {
15573  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
15574  continue;
15575  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
15576  Display->Update();
15577  }
15578  OverlayPlotted = false;
15579  }
15580  Utilities->CallLogPop(350);
15581 }
15582 
15583 // ---------------------------------------------------------------------------
15584 
15585 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
15586 {
15587  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
15588  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
15589  {
15590  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
15591  }
15592  Utilities->CallLogPop(120);
15593  return AllRoutesVector.at(At);
15594 }
15595 
15596 // ---------------------------------------------------------------------------
15597 // ---------------------------------------------------------------------------
15598 
15600 {
15601  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
15602  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
15603  {
15604  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
15605  }
15606  Utilities->CallLogPop(121);
15607  return AllRoutesVector.at(At);
15608 }
15609 
15610 // ---------------------------------------------------------------------------
15611 
15612 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
15613 /*
15614  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
15615 */
15616 {
15617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
15618  for(unsigned int a = 0; a < AllRoutesSize(); a++)
15619  {
15620  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
15621  }
15622  Utilities->CallLogPop(351);
15623 }
15624 
15625 // ---------------------------------------------------------------------------
15626 
15627 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
15628 {
15629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
15630  for(unsigned int a = 0; a < AllRoutesSize(); a++)
15631  {
15632  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
15633  }
15634  Utilities->CallLogPop(1706);
15635 }
15636 
15637 // ---------------------------------------------------------------------------
15638 
15639 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
15640 /*
15641  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
15642  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
15643  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
15644  the element that matches H & V. If ConsecSignalsRoute ensure only truncate to a signal, else prevent
15645  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
15646  length (train length).
15647 */
15648 {
15649  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
15650  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignalsRoute));
15651  for(unsigned int a = 0; a < AllRoutesSize(); a++)
15652  {
15653  TTruncateReturnType ReturnFlag;
15654  RouteTruncateFlag = true;
15655 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
15656  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute, ReturnFlag);
15657  RouteTruncateFlag = false;
15658  if(ReturnFlag == NotInRoute)
15659  continue;
15660  else if(ReturnFlag == InRouteTrue)
15661  {
15662  Utilities->CallLogPop(352);
15663  return true;
15664  }
15665  else if(ReturnFlag == InRouteFalse)
15666  {
15667  Utilities->CallLogPop(353);
15668  return false;
15669  }
15670  }
15671  Utilities->CallLogPop(354);
15672  return false;
15673 }
15674 
15675 // ---------------------------------------------------------------------------
15676 
15677 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
15678 /*
15679  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
15680  is found it returns true (for crossovers returns true whichever track the route is on), else returns false.
15681 */
15682 {
15683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
15684  AnsiString(LinkPos));
15685  if(TrackVectorPosition == -1) // allows for continuation entries & exits
15686  {
15687  Utilities->CallLogPop(355);
15688  return false;
15689  }
15690  THVPair Route2MultiMapKeyPair;
15691 
15692  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
15693  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
15694  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
15695  TRoute2MultiMapIterator Route2MultiMapIterator;
15696 
15697  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
15698  {
15699  Utilities->CallLogPop(356);
15700  return false;
15701  }
15702  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
15703  {
15704  Utilities->CallLogPop(1422);
15705  return true;
15706  }
15707  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
15708  {
15709  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
15710 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15711 // realised after writing this that can't be points as would have been covered above, but leave anyway
15712  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
15713  Route2MultiMapIterator->second.second);
15714  EntryLinkPos = PrefDirElement1.ELinkPos;
15715  ExitLinkPos = PrefDirElement1.XLinkPos;
15716  EntryLink = PrefDirElement1.Link[EntryLinkPos];
15717  ExitLink = PrefDirElement1.Link[ExitLinkPos];
15718  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
15719  {
15720  Utilities->CallLogPop(357);
15721  return true;
15722  }
15723  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
15724  {
15725  Utilities->CallLogPop(358);
15726  return true;
15727  }
15728  }
15729  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
15730  {
15731  Utilities->CallLogPop(1423);
15732  return true;
15733  }
15734  Utilities->CallLogPop(363);
15735  return false; // none found
15736 }
15737 
15738 // ---------------------------------------------------------------------------
15739 
15740 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
15741  Graphics::TBitmap* &EntryDirectionGraphicPtr)
15742 /*
15743  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
15744  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
15745  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
15746  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
15747  for replotting of AutoSigsRoutes.
15748 */
15749 {
15750  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
15751  AnsiString(LinkPos));
15752  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
15753  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
15754  if(TrackVectorPosition == -1)
15755  {
15756  Utilities->CallLogPop(364);
15757  return NoRoute; // allows for continuation entries & exits
15758  }
15759  THVPair Route2MultiMapKeyPair;
15760 
15761  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
15762  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
15763  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
15764  TRoute2MultiMapIterator Route2MultiMapIterator;
15765 
15766  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
15767  {
15768  Utilities->CallLogPop(365);
15769  return NoRoute; // none found
15770  }
15771  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
15772  {
15773  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
15774 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15775  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
15776  Route2MultiMapIterator->second.second);
15777  EntryLinkPos = PrefDirElement1.ELinkPos;
15778  ExitLinkPos = PrefDirElement1.XLinkPos;
15779  EntryLink = PrefDirElement1.Link[EntryLinkPos];
15780  ExitLink = PrefDirElement1.Link[ExitLinkPos];
15781  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
15782  {
15783  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
15784  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
15785  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
15786  {
15787  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
15788  }
15789  if(PrefDirElement1.AutoSignals)
15790  {
15791  Utilities->CallLogPop(366);
15792  return AutoSigsRoute;
15793  }
15794  else
15795  {
15796  Utilities->CallLogPop(367);
15797  return NotAutoSigsRoute;
15798  }
15799  }
15800  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
15801  {
15802  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
15803  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
15804  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
15805  {
15806  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
15807  }
15808  if(PrefDirElement1.AutoSignals)
15809  {
15810  Utilities->CallLogPop(368);
15811  return AutoSigsRoute;
15812  }
15813  else
15814  {
15815  Utilities->CallLogPop(369);
15816  return NotAutoSigsRoute;
15817  }
15818  }
15819  }
15820  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
15821  {
15822  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
15823  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
15824 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15825  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
15826  EntryLinkPos = PrefDirElement2.ELinkPos;
15827  ExitLinkPos = PrefDirElement2.XLinkPos;
15828  EntryLink = PrefDirElement2.Link[EntryLinkPos];
15829  ExitLink = PrefDirElement2.Link[ExitLinkPos];
15830  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
15831  {
15832  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
15833  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
15834  {
15835  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
15836  }
15837  if(PrefDirElement2.AutoSignals)
15838  {
15839  Utilities->CallLogPop(370);
15840  return AutoSigsRoute;
15841  }
15842  else
15843  {
15844  Utilities->CallLogPop(371);
15845  return NotAutoSigsRoute;
15846  }
15847  }
15848  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
15849  {
15850  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
15851  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
15852  {
15853  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
15854  }
15855  if(PrefDirElement2.AutoSignals)
15856  {
15857  Utilities->CallLogPop(372);
15858  return AutoSigsRoute;
15859  }
15860  else
15861  {
15862  Utilities->CallLogPop(373);
15863  return NotAutoSigsRoute;
15864  }
15865  }
15866 
15867  ItPair.second--; // the second iterator points one past the last matching value
15868  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
15869  EntryLinkPos = PrefDirElement3.ELinkPos;
15870  ExitLinkPos = PrefDirElement3.XLinkPos;
15871  EntryLink = PrefDirElement3.Link[EntryLinkPos];
15872  ExitLink = PrefDirElement3.Link[ExitLinkPos];
15873  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
15874  {
15875  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
15876  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
15877  {
15878  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
15879  }
15880  if(PrefDirElement3.AutoSignals)
15881  {
15882  Utilities->CallLogPop(374);
15883  return AutoSigsRoute;
15884  }
15885  else
15886  {
15887  Utilities->CallLogPop(375);
15888  return NotAutoSigsRoute;
15889  }
15890  }
15891  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
15892  {
15893  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
15894  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
15895  {
15896  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
15897  }
15898  if(PrefDirElement3.AutoSignals)
15899  {
15900  Utilities->CallLogPop(376);
15901  return AutoSigsRoute;
15902  }
15903  else
15904  {
15905  Utilities->CallLogPop(377);
15906  return NotAutoSigsRoute;
15907  }
15908  }
15909  }
15910  Utilities->CallLogPop(378);
15911  return NoRoute; // none found
15912 }
15913 
15914 // ---------------------------------------------------------------------------
15915 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
15916 /*
15917  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
15918  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
15919 */
15920 {
15921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
15922  AnsiString(LinkPos));
15923  if(TrackVectorPosition == -1)
15924  {
15925  RouteNumber = -1;
15926  Utilities->CallLogPop(379);
15927  return NoRoute; // allows for continuation & buffer entries & exits
15928  }
15929  THVPair Route2MultiMapKeyPair;
15930 
15931  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
15932  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
15933  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
15934  TRoute2MultiMapIterator Route2MultiMapIterator;
15935 
15936  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
15937  {
15938  RouteNumber = -1;
15939  Utilities->CallLogPop(380);
15940  return NoRoute; // none found
15941  }
15942  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
15943  {
15944  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
15945 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15946  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
15947  Route2MultiMapIterator->second.second);
15948  EntryLinkPos = PrefDirElement1.ELinkPos;
15949  ExitLinkPos = PrefDirElement1.XLinkPos;
15950  EntryLink = PrefDirElement1.Link[EntryLinkPos];
15951  ExitLink = PrefDirElement1.Link[ExitLinkPos];
15952  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
15953  {
15954  RouteNumber = Route2MultiMapIterator->second.first;
15955  if(PrefDirElement1.AutoSignals)
15956  {
15957  Utilities->CallLogPop(381);
15958  return AutoSigsRoute;
15959  }
15960  else
15961  {
15962  Utilities->CallLogPop(382);
15963  return NotAutoSigsRoute;
15964  }
15965  }
15966  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
15967  {
15968  RouteNumber = Route2MultiMapIterator->second.first;
15969  if(PrefDirElement1.AutoSignals)
15970  {
15971  Utilities->CallLogPop(383);
15972  return AutoSigsRoute;
15973  }
15974  else
15975  {
15976  Utilities->CallLogPop(384);
15977  return NotAutoSigsRoute;
15978  }
15979  }
15980  }
15981  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
15982  {
15983  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
15984  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
15985 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15986  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
15987  EntryLinkPos = PrefDirElement2.ELinkPos;
15988  ExitLinkPos = PrefDirElement2.XLinkPos;
15989  EntryLink = PrefDirElement2.Link[EntryLinkPos];
15990  ExitLink = PrefDirElement2.Link[ExitLinkPos];
15991  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
15992  {
15993  RouteNumber = ItPair.first->second.first;
15994  if(PrefDirElement2.AutoSignals)
15995  {
15996  Utilities->CallLogPop(385);
15997  return AutoSigsRoute;
15998  }
15999  else
16000  {
16001  Utilities->CallLogPop(386);
16002  return NotAutoSigsRoute;
16003  }
16004  }
16005  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
16006  {
16007  RouteNumber = ItPair.first->second.first;
16008  if(PrefDirElement2.AutoSignals)
16009  {
16010  Utilities->CallLogPop(387);
16011  return AutoSigsRoute;
16012  }
16013  else
16014  {
16015  Utilities->CallLogPop(388);
16016  return NotAutoSigsRoute;
16017  }
16018  }
16019 
16020  ItPair.second--; // the second iterator points one past the last matching value
16021  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
16022  EntryLinkPos = PrefDirElement3.ELinkPos;
16023  ExitLinkPos = PrefDirElement3.XLinkPos;
16024  EntryLink = PrefDirElement3.Link[EntryLinkPos];
16025  ExitLink = PrefDirElement3.Link[ExitLinkPos];
16026  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
16027  {
16028  RouteNumber = ItPair.second->second.first;
16029  if(PrefDirElement3.AutoSignals)
16030  {
16031  Utilities->CallLogPop(389);
16032  return AutoSigsRoute;
16033  }
16034  else
16035  {
16036  Utilities->CallLogPop(390);
16037  return NotAutoSigsRoute;
16038  }
16039  }
16040  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
16041  {
16042  RouteNumber = ItPair.second->second.first;
16043  if(PrefDirElement3.AutoSignals)
16044  {
16045  Utilities->CallLogPop(391);
16046  return AutoSigsRoute;
16047  }
16048  else
16049  {
16050  Utilities->CallLogPop(392);
16051  return NotAutoSigsRoute;
16052  }
16053  }
16054  }
16055  RouteNumber = -1;
16056  Utilities->CallLogPop(393);
16057  return NoRoute; // none found
16058 }
16059 
16060 // ---------------------------------------------------------------------------
16061 
16062 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
16063 /*
16064  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
16065  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
16066  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
16067  and Route2MultiMap.
16068 */
16069 {
16070  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
16071  TOneRoute EmptyRoute;
16072 
16073  EmptyRoute.RouteID = NextRouteID;
16074  NextRouteID++;
16075 
16076  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16077  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16078  {
16079  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
16080  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
16081  }
16082  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
16083  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
16084 
16085  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
16086  Utilities->CallLogPop(394);
16087 }
16088 
16089 // ---------------------------------------------------------------------------
16090 
16092 /*
16093  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
16094  that is already in Route is used.
16095 */
16096 {
16097  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
16098  TOneRoute EmptyRoute;
16099 
16100  EmptyRoute.RouteID = Route->RouteID;
16101 
16102  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16103  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16104  {
16105  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
16106  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
16107  }
16108  Utilities->CallLogPop(1579);
16109 }
16110 
16111 // ---------------------------------------------------------------------------
16112 
16113 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
16114 /*
16115  When attaching a new route section to an existing route, it is sometimes necessary to erase the
16116  original route and create a new composite route. This function Erases all elements in the route
16117  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
16118  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
16119  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
16120  that are greater than the route number that is removed. The LockedRouteVector as also searched
16121  and if any relate to the route that has been cleared they are erased too, but the fact that one
16122  has been found is recorded so that it can be re-established later.
16123 */
16124 {
16125  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
16126  THVPair Route2MultiMapKeyPair;
16127  TRoute2MultiMapEntry Route2MultiMapEntry;
16128  TRoute2MultiMapIterator Route2MultiMapIterator;
16129 
16130 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
16131 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
16132 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
16133 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
16134 // If so the locked route is removed from the locked vector and is lost.
16135  LockedRouteTruncateTrackVectorPosition = 0;
16136  LockedRouteLastTrackVectorPosition = 0;
16137  LockedRouteLastXLinkPos = 0;
16138  LockedRouteLockStartTime = TDateTime(0);
16139  if(!LockedRouteVector.empty())
16140  {
16141  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16142  {
16143  if(LRVIT->RouteNumber == RouteNumber)
16144  {
16145  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
16146  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
16147  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
16148  LockedRouteLockStartTime = LRVIT->LockStartTime;
16149  LockedRouteFoundDuringRouteBuilding = true;
16150  LockedRouteVector.erase(LRVIT);
16151  }
16152  }
16153  }
16154 
16155  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
16156  {
16157  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
16158  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
16159  }
16160  Utilities->CallLogPop(395);
16161 }
16162 
16163 // ---------------------------------------------------------------------------
16164 
16166  TRoute2MultiMapIterator &Route2MultiMapIterator)
16167 /*
16168  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
16169  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
16170  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
16171  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
16172  are given for failure.
16173 */
16174 {
16175  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16176  AnsiString(VLoc) + "," + AnsiString(ELink));
16177  TRouteElementPair ReturnPair;
16178 
16179  ReturnPair.first = -1;
16180  ReturnPair.second = 0;
16181  THVPair Route2MultiMapKeyPair;
16182 
16183  Route2MultiMapKeyPair.first = HLoc;
16184  Route2MultiMapKeyPair.second = VLoc;
16185  TRoute2MultiMapEntry Route2MultiMapEntry;
16186 
16187  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16188  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16189 
16190  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16191  Route2MultiMapIterator = ItPair.first;
16192 
16193  if(ItPair.first == ItPair.second)
16194  {
16195  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
16196  }
16197 
16198  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
16199  {
16200  ReturnPair.first = ItPair.first->second.first;
16201  ReturnPair.second = ItPair.first->second.second;
16202  Route2MultiMapIterator = ItPair.first;
16203  Utilities->CallLogPop(396);
16204  return ReturnPair;
16205  }
16206  ItPair.first++;
16207  if(ItPair.first == ItPair.second)
16208  {
16209  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
16210  }
16211  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
16212  {
16213  ReturnPair.first = ItPair.first->second.first;
16214  ReturnPair.second = ItPair.first->second.second;
16215  Route2MultiMapIterator = ItPair.first;
16216  Utilities->CallLogPop(397);
16217  return ReturnPair;
16218  }
16219  Utilities->CallLogPop(398);
16220  return ReturnPair;
16221 }
16222 
16223 // ---------------------------------------------------------------------------
16224 
16225 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
16226 /*
16227  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
16228  Examines Route2MultiMap and returns true if oa route is found with the passed values of H, V and ELink.
16229  RouteNumber (route position in AllRoutes vector is returned as a reference.
16230  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
16231  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
16232 */
16233 {
16234  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
16235  AnsiString(VLoc) + "," + AnsiString(ELink));
16236  THVPair Route2MultiMapKeyPair;
16237 
16238  Route2MultiMapKeyPair.first = HLoc;
16239  Route2MultiMapKeyPair.second = VLoc;
16240  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16241 
16242  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16243 
16244  if(ItPair.first == ItPair.second)
16245  {
16246  RouteNumber = -1;
16247  Utilities->CallLogPop(2032);
16248  return false;
16249  }
16250 
16251  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
16252  {
16253  RouteNumber = ItPair.first->second.first;
16254  Utilities->CallLogPop(2033);
16255  return true;
16256  }
16257 
16258  ItPair.first++;
16259 
16260  if(ItPair.first == ItPair.second)
16261  {
16262  RouteNumber = -1;
16263  Utilities->CallLogPop(2034);
16264  return false;
16265  }
16266 
16267  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
16268  {
16269  RouteNumber = ItPair.first->second.first;
16270  Utilities->CallLogPop(2035);
16271  return true;
16272  }
16273  RouteNumber = -1;
16274  Utilities->CallLogPop(2036);
16275  return false;
16276 }
16277 
16278 // ---------------------------------------------------------------------------
16279 
16280 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
16281 /*
16282  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
16283  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
16284  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
16285  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
16286  Called by TAllRoutes::AddRouteElement.
16287 */
16288 {
16289  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16290  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
16291  THVPair Route2MultiMapKeyPair;
16292 
16293  Route2MultiMapKeyPair.first = HLoc;
16294  Route2MultiMapKeyPair.second = VLoc;
16295  TRoute2MultiMapEntry Route2MultiMapEntry;
16296 
16297  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16298  TRouteElementPair RouteElementPair;
16299 
16300  RouteElementPair.first = RouteNumber;
16301  RouteElementPair.second = RouteElementNumber;
16302  Route2MultiMapEntry.second = RouteElementPair;
16303 
16304  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
16305  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
16306  {
16307  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
16308  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
16309  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
16310  {
16311  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
16312  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
16313  {
16314  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16315  }
16316  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
16317  }
16318  else
16319  // same ELink so have an error
16320  {
16321  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16322  }
16323  }
16324  else
16325  Route2MultiMap.insert(Route2MultiMapEntry);
16326 // element at H&V not found in map so insert it
16327  Utilities->CallLogPop(399);
16328 }
16329 
16330 // ---------------------------------------------------------------------------
16331 
16333 /*
16334  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
16335  and the second in the reference SecondPair. If there's only one then it's the function return
16336 */
16337 {
16338  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16339  AnsiString(VLoc));
16341 
16342  TempPair.first = -1;
16343  TempPair.second = 0;
16344  SecondPair = TempPair;
16345  TRoute2MultiMapIterator Route2MultiMapIterator;
16346  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
16347  THVPair Route2MultiMapKeyPair;
16348 
16349  Route2MultiMapKeyPair.first = HLoc;
16350  Route2MultiMapKeyPair.second = VLoc;
16351  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16352  {
16353  Utilities->CallLogPop(400);
16354  return TempPair;
16355  }
16356  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16357  {
16358  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16359  Utilities->CallLogPop(401);
16360  return Route2MultiMapIterator->second;
16361  }
16362  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16363  {
16364  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16365  TempPair = ItRange.first->second;
16366  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
16367  Utilities->CallLogPop(402);
16368  return TempPair;
16369  }
16370  Utilities->CallLogPop(403);
16371  return TempPair;
16372 }
16373 
16374 // ---------------------------------------------------------------------------
16375 
16376 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
16377 /*
16378  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
16379  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
16380 */
16381 {
16382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
16383  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16384  {
16385  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
16386  {
16387  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
16388  TAllRoutes::TRouteElementPair SecondPair;
16389  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
16390  if(RouteElementPair.first == -1)
16391  // failed to find element in multimap
16392  {
16393  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
16394  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
16395  }
16396  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
16397  // neither pair has expected route number
16398  {
16399  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16400  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
16401  (AnsiString)Caller);
16402  }
16403  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
16404  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
16405  {
16406  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16407  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
16408  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
16409  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
16410  }
16411  }
16412  }
16413  unsigned int SizeVal = 0;
16414 
16415 // check map and sum of route sizes match
16416  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16417  {
16418  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
16419  }
16420  if(SizeVal != Route2MultiMap.size())
16421  {
16422  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
16423  (AnsiString)Caller);
16424  }
16425  Utilities->CallLogPop(404);
16426  return;
16427 }
16428 
16429 // ---------------------------------------------------------------------------
16430 
16431 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
16432 /*
16433  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
16434  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
16435  exceed that for the erased route. Where this is so the RouteNumber is decremented.
16436 */
16437 {
16438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
16439  if(!Route2MultiMap.empty())
16440  {
16441  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16442  {
16443  if(Route2MultiMapIterator->second.first > RouteNumber)
16444  Route2MultiMapIterator->second.first--;
16445  }
16446  }
16447  Utilities->CallLogPop(405);
16448 }
16449 
16450 // ---------------------------------------------------------------------------
16451 
16452 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
16453 /*
16454  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
16455  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
16456  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
16457 */
16458 {
16459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
16460  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
16461  if(!Route2MultiMap.empty())
16462  {
16463  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16464  {
16465  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
16466  Route2MultiMapIterator->second.second--;
16467  }
16468  }
16469  Utilities->CallLogPop(406);
16470 }
16471 
16472 // ---------------------------------------------------------------------------
16473 
16474 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
16475 /*
16476  Erases the route element from Route2MultiMap and from the PrefDirVector.
16477  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
16478  decremented if they are greater than the element number removed, and if the entire route is removed
16479  then the route numbers are also decremented in the map for route numbers that are greater than the route
16480  number that is removed.
16481 */
16482 {
16483  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
16484  AnsiString(ELink));
16485  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
16486  TRoute2MultiMapIterator Route2MultiMapIterator;
16487 
16488  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
16489  if(RequiredRoutePair.first == -1)
16490  {
16491  throw Exception("Failed to find route element in RemoveRouteElement");
16492  }
16493  Route2MultiMap.erase(Route2MultiMapIterator);
16494  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
16495 
16496 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
16497  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
16498 
16499  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
16500  {
16501  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
16502  }
16503 
16504 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
16505 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
16506 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
16507 // to check if a route element is present, and the element has already been removed from the map - see above.
16508 
16509 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
16510 /*
16511  int LockedVectorNumber = -1;
16512  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
16513  {
16514  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
16515  }
16516 */
16517 
16518 // erase element from route
16519  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
16520  RequiredRoutePair.second)));
16521 // CheckMapAndRoutes();//test - drop - tested below
16522 
16523 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
16524 // be so as continuation exit is at the end of the route, and truncation is from the end
16526  {
16528  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16529  AutoSigVectorIT--)
16530  {
16531  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
16532  {
16533  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
16534  }
16535  }
16536  }
16537 
16538 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
16539 // and adjust all the corresponding route numbers
16540  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
16541  {
16542  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
16543  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
16544  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
16545 
16546 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
16547  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
16548  it is erased then - see TInterface::ApproachLocking
16549 
16550  if(LockedVectorNumber > -1)
16551  {
16552  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
16553  }
16554 */
16555  // decrement route numbers in the locked route vector whether or not this route is a locked route
16556  if(!LockedRouteVector.empty())
16557  {
16558  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16559  {
16560  if(LRVIT->RouteNumber > RequiredRoutePair.first)
16561  {
16562  LRVIT->RouteNumber--;
16563  }
16564  }
16565  }
16566 
16568  {
16570  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16571  AutoSigVectorIT--)
16572  {
16573  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
16574  AutoSigVectorIT->RouteNumber--;
16575  }
16576  }
16577  }
16578  CheckMapAndRoutes(7); // test
16579  Utilities->CallLogPop(407);
16580 }
16581 
16582 // ---------------------------------------------------------------------------
16583 
16584 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
16585 /*
16586  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
16587  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
16588  since that catches all route elements wherever created
16589 */
16590 {
16591  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
16592  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
16593  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
16594  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
16595  Utilities->CallLogPop(408);
16596 }
16597 
16598 // ---------------------------------------------------------------------------
16599 
16600 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
16601 /*
16602  Enter with signal at TrackVectorElement already set to red by the passing train.
16603  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
16604  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
16605  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
16606  case the function sets no further signals.
16607 */
16608 {
16609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
16610  "," + AnsiString(XLinkPos));
16611  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
16612  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
16613 
16614  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
16615  if(RouteElementPair.first == -1)
16616  {
16617  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
16618  }
16619  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
16620 
16621  RequiredPair = RouteElementPair;
16622  if(RouteElement.XLinkPos != XLinkPos)
16623  {
16624  if(SecondPair.first != -1)
16625  {
16626  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
16627  RequiredPair = SecondPair;
16628  if(RouteElement.XLinkPos != XLinkPos)
16629  {
16630  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
16631  }
16632  }
16633  else
16634  {
16635  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
16636  }
16637  }
16638 
16639 // new function
16640  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
16641  Utilities->CallLogPop(409);
16642 }
16643 
16644 // ---------------------------------------------------------------------------
16645 
16646 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
16647 /*
16648  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
16649  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
16650  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
16651  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
16652  to 2 for successive calls.
16653  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
16654  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
16655  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
16656  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
16657 */
16658 {
16659  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
16660  AnsiString(AccessNumber));
16661  TPrefDirElement RouteElement;
16662  int Attribute = AccessNumber + 1;
16663 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
16664  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
16665 
16666  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
16667  {
16668  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
16669  }
16670  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
16671  {
16672  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
16673  }
16674  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
16675  x).XLinkPos] != End)
16676  {
16677  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
16678  }
16679 // new function
16680  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
16681  Utilities->CallLogPop(410);
16682 }
16683 
16684 // ---------------------------------------------------------------------------
16685 
16686 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
16687 /*
16688  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
16689  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
16690  or (b) in a linked rear route, in which case the function sets no further signals.
16691 
16692  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
16693  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
16694  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
16695  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
16696  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
16697  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
16698  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
16699  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
16700  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
16701  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
16702  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
16703  found behind the train.
16704 
16705  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
16706  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
16707  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
16708  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
16709  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
16710  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
16711  a route.
16712 
16713  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
16714  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
16715  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 and continue working backwards
16716  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
16717  reference. If no train is found before the beginning of the route is reached the function returns true.
16718 
16719 */
16720 {
16721  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
16722  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
16723  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
16724  int RearwardLinkedRouteNumber;
16725 
16726  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
16727  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
16728  // signal value in the route for use in further linked routes
16729  {
16730  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
16731  {
16732  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
16733  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16734  {
16735  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
16736  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
16737  break;
16738  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
16739  // flash LCs on those routes
16740  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
16741  }
16742  }
16743  }
16744  else
16745  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
16746  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
16747  {
16748  int TrainID, TrainPosition, BehindTrainPosition;
16749  bool FoundTrain = false, BehindTrain = false;
16750  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
16751  {
16752  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
16753  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
16754  TrainID = TrackElement.TrainIDOnElement;
16755  if(TrackElement.TrackType == Bridge)
16756  {
16757  if(PrefDirElement.XLinkPos < 2)
16758  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
16759  else
16760  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
16761  }
16762  if(TrainID == -1)
16763  continue;
16764  else
16765  {
16766  FoundTrain = true;
16767  TrainPosition = x;
16768  break;
16769  }
16770  }
16771  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
16772  {
16773  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
16774  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
16775  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
16776  // need the element behind the rearmost train.
16777  {
16778  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
16779  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
16780  TrainID = TrackElement.TrainIDOnElement;
16781  if(TrackElement.TrackType == Bridge)
16782  {
16783  if(PrefDirElement.XLinkPos < 2)
16784  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
16785  else
16786  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
16787  }
16788  if(TrainID != -1)
16789  continue; // still on train
16790  else
16791  {
16792  BehindTrain = true;
16793  BehindTrainPosition = x;
16794  break;
16795  }
16796  }
16797  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
16798  // so on for as many trains as there are on the single route
16799  {
16800  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
16801  // first signal behind train to be red
16802  }
16803  }
16804  }
16805  Utilities->CallLogPop(411);
16806 }
16807 
16808 // ---------------------------------------------------------------------------
16809 
16810 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
16811 {
16812 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
16813  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
16814  first signal is red, then OK
16815 */
16816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
16817  AnsiString(RouteTruncatePosition));
16818  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
16819  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
16820  TPrefDirElement PrefDirElement, FirstElement;
16821  TTrackElement TrackElement;
16822  bool ExamineRoute = true;
16823 
16824  while(ExamineRoute)
16825  {
16826  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
16827  {
16828  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
16829  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
16830  TrainID = TrackElement.TrainIDOnElement;
16831  if(TrackElement.TrackType == Bridge)
16832  {
16833  if(PrefDirElement.XLinkPos < 2)
16834  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
16835  else
16836  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
16837  }
16838  if(TrainID > -1)
16839  {
16840  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
16841  { //any trains further back in route will be protected by the red signal behind the stopped train
16842  Utilities->CallLogPop(412);
16843  return false;
16844  }
16845  //added after v2.4.1 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
16846  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
16847  //other way & can cancel the route
16848  {
16849  Utilities->CallLogPop(2203);
16850  return false;
16851  }
16852  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
16853  return true; //TrainOccupyingRoute which is outside this function but also causes route locking)
16854  }
16855  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
16856  {
16857  if(TrackElement.Attribute == 0)
16858  {
16859  Utilities->CallLogPop(413);
16860  return false; // OK, red signal in front of a train
16861  }
16862  SignalCount++;
16863  if(SignalCount >= 3)
16864  {
16865  Utilities->CallLogPop(414);
16866  return false;
16867  }
16868  }
16869  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
16870  // ElinkPos because working back along PrefDir to beginning
16871  {
16872  Utilities->CallLogPop(415);
16873  return false; // test - set to true to create a locked buffer-ended route, false for normal use
16874  }
16875  }
16876  //now look at linked rearwards routes
16877  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
16878  StartPosition = CurrentRoute.PrefDirSize() - 1;
16879  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
16880  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16881  {
16882  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
16883  ExamineRoute = true;
16884  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
16885  }
16886  else
16887  {
16888  // here check for a train on the element immediately before the first route element
16889  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
16890  TrainID = PriorTrackElement.TrainIDOnElement;
16891  if(PriorTrackElement.TrackType == Bridge)
16892  {
16893  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
16894  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
16895  else
16896  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
16897  }
16898  if(TrainID > -1)
16899  {
16900  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
16901  {
16902  Utilities->CallLogPop(748);
16903  return false;
16904  }
16905  //added after v2.4.1 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
16906  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
16907  //other way & can cancel the route
16908  {
16909  Utilities->CallLogPop(2204);
16910  return false;
16911  }
16912  Utilities->CallLogPop(1962);
16913  return true; //otherwise need to lock the route
16914  }
16915  ExamineRoute = false;
16916  }
16917  }
16918 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
16919 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
16920  Utilities->CallLogPop(416);
16921  return false;
16922 }
16923 
16924 // ---------------------------------------------------------------------------
16925 
16926 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
16927  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
16928 {
16929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
16930  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
16931  TPrefDirElement InternalPrefDirElement; // blank element
16932 
16933  PrefDirElement = InternalPrefDirElement;
16934  if(LockedRouteVector.empty())
16935  {
16936  Utilities->CallLogPop(417);
16937  return false;
16938  }
16939 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
16940 // even if some elements have been removed from the front by a train
16941  bool InLockedRoute = false;
16942 
16943  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16944  {
16945  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
16946  { // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
16947  // doesn't arise)
16948  InLockedRoute = true;
16949  break;
16950  }
16951  }
16952  if(!InLockedRoute)
16953  {
16954  Utilities->CallLogPop(418);
16955  return false;
16956  }
16957 
16958  int RouteNumber, VectorCount = 0;
16959  TRouteType RouteType;
16960 
16961  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16962  {
16963  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
16964  if(RouteType == NoRoute)
16965  continue;
16966  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
16967  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
16968  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
16969  {
16970  throw Exception
16971  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
16972  }
16973  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
16974  {
16975  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
16976  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
16977  {
16978  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
16979  {
16980  PrefDirElement = InternalPrefDirElement;
16981  LockedVectorNumber = VectorCount;
16982  Utilities->CallLogPop(419);
16983  return true;
16984  }
16985  }
16986  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
16987  {
16988  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
16989  {
16990  PrefDirElement = InternalPrefDirElement;
16991  LockedVectorNumber = VectorCount;
16992  Utilities->CallLogPop(420);
16993  return true;
16994  }
16995  else
16996  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
16997  }
16998  }
16999  VectorCount++;
17000  }
17001  Utilities->CallLogPop(421);
17002  return false;
17003 }
17004 
17005 // ---------------------------------------------------------------------------
17006 
17008 {
17009  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
17010  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17011  {
17012  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
17013  {
17014  Utilities->CallLogPop(963);
17015  return x;
17016  }
17017  }
17018  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
17019 }
17020 
17021 // ---------------------------------------------------------------------------
17022 
17024  // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
17025  // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
17026 {
17027  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17028  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17029  {
17030  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
17031  {
17032  Utilities->CallLogPop(2039);
17033  return true;
17034  }
17035  }
17036  Utilities->CallLogPop(2040);
17037  return false;
17038 }
17039 
17040 // ---------------------------------------------------------------------------
17041 
17043 {
17044  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17045  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17046  {
17047  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
17048  {
17049  Utilities->CallLogPop(964);
17050  return GetFixedRouteAt(159, x);
17051  }
17052  }
17053  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17054 }
17055 
17056 // ---------------------------------------------------------------------------
17057 
17059 {
17060  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
17061  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17062  {
17063  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
17064  {
17065  Utilities->CallLogPop(965);
17066  return GetModifiableRouteAt(15, x);
17067  }
17068  }
17069  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17070 }
17071 
17072 // ---------------------------------------------------------------------------
17073 
17074 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
17075 {
17076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
17077  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
17078  Utilities->SaveFileInt(OutFile, NextRouteID);
17079  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17080  {
17081  TOneRoute OneRoute = GetFixedRouteAt(165, x);
17082  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
17083  OneRoute.SavePrefDirVector(6, OutFile);
17084  }
17085  Utilities->CallLogPop(1442);
17086 }
17087 
17088 // ---------------------------------------------------------------------------
17089 
17090 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
17091 {
17092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
17093  int NumberOfRoutes;
17094 
17095  NumberOfRoutes = Utilities->LoadFileInt(InFile);
17096  NextRouteID = Utilities->LoadFileInt(InFile);
17097  for(int x = 0; x < NumberOfRoutes; x++)
17098  {
17099  TOneRoute OneRoute; // empty route
17100  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
17101  OneRoute.LoadPrefDir(2, InFile);
17103  {
17104  StoreOneRouteAfterSessionLoad(0, &OneRoute);
17105  }
17106  else
17107  {
17108  Utilities->CallLogPop(1443);
17109  return false;
17110  }
17111  }
17112  Utilities->CallLogPop(1444);
17113  return true;
17114 }
17115 
17116 // ---------------------------------------------------------------------------
17117 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
17118 {
17119  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
17120  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
17121 
17122  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
17123  {
17124  Utilities->CallLogPop(1445);
17125  return false;
17126  }
17127  int NextID = Utilities->LoadFileInt(InFile);
17128 
17129  if((NextID < 0) || (NextID > 1000000))
17130  {
17131  Utilities->CallLogPop(1446);
17132  return false;
17133  }
17134  for(int x = 0; x < NumberOfRoutes; x++)
17135  {
17136  int RouteID = Utilities->LoadFileInt(InFile);
17137  if((RouteID < 0) || (RouteID > 20000))
17138  {
17139  Utilities->CallLogPop(1447);
17140  return false;
17141  }
17142  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
17143  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
17144  {
17145  Utilities->CallLogPop(1448);
17146  return false;
17147  }
17148  }
17149  Utilities->CallLogPop(1449);
17150  return true;
17151 }
17152 
17153 // ---------------------------------------------------------------------------
17154 
17155 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
17156 { // return true for a loop
17157  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
17158  AnsiString(StartPosition));
17159  if(EndPosition == StartPosition)
17160  {
17161  Utilities->CallLogPop(1839);
17162  return true; // shouldn't happen but treat as a loop if does
17163  }
17164 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
17165  int TVPos = EndPosition;
17166  int LkPos = EndXLinkPos;
17167 
17168  while(TrackIsInARoute(15, TVPos, LkPos))
17169  {
17170  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos];
17171  int NewLkPos = -1;
17172  if(NewTVPos > -1)
17173  {
17174  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
17175  if(NewLkPos == -1)
17176  {
17177  Utilities->CallLogPop(1840);
17178  return true; // shouldn't arise but treat as loop if does
17179  }
17180  }
17181  else // reached a buffer or continuation
17182  {
17183  Utilities->CallLogPop(1841);
17184  return false;
17185  }
17186  TVPos = NewTVPos;
17187  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
17188  {
17189  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
17190  {
17191  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
17192  LkPos = 1;
17193  else
17194  LkPos = 3;
17195  }
17196  else
17197  LkPos = 0;
17198  }
17199  else
17200  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
17201  if(TVPos == StartPosition)
17202  {
17203  Utilities->CallLogPop(1842);
17204  return true; // it is a loop
17205  }
17206  }
17207  Utilities->CallLogPop(1843);
17208  return false; // reached end of route so not a loop
17209 }
17210 
17211 // ---------------------------------------------------------------------------
17212 
17213 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17214 /*
17215  Track geometry allows diagonals to cross without occupying the same track element, so when
17216  route plotting it is necessary to check if there is an existing route or a train on such a crossing
17217  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
17218  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17219  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17220  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17221  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17222  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17223  Each of these is examined in turn for each route element in the relevant position.
17224 
17225  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
17226  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
17227  that returns false in all cases (including elements & links not present) except train present.
17228 */
17229 {
17230  int TrainID; // not used in this function
17231 
17232  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
17233  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
17234  TPrefDirElement TempPrefDirElement;
17235  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17236 
17237  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
17238  if(FirstPair.first > -1)
17239  {
17240  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
17241  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17242  {
17243  Utilities->CallLogPop(310);
17244  return true;
17245  }
17246  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17247  {
17248  Utilities->CallLogPop(311);
17249  return true;
17250  }
17251  }
17252  if(SecondPair.first > -1)
17253  {
17254  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
17255  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17256  {
17257  Utilities->CallLogPop(312);
17258  return true;
17259  }
17260  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17261  {
17262  Utilities->CallLogPop(313);
17263  return true;
17264  }
17265  }
17266 
17267  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
17268  9, TrainID)))
17269  {
17270  Utilities->CallLogPop(1997);
17271  return true;
17272  }
17273 
17274  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
17275  if(FirstPair.first > -1)
17276  {
17277  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
17278  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17279  {
17280  Utilities->CallLogPop(314);
17281  return true;
17282  }
17283  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17284  {
17285  Utilities->CallLogPop(315);
17286  return true;
17287  }
17288  }
17289  if(SecondPair.first > -1)
17290  {
17291  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
17292  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17293  {
17294  Utilities->CallLogPop(316);
17295  return true;
17296  }
17297  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17298  {
17299  Utilities->CallLogPop(317);
17300  return true;
17301  }
17302  }
17303 
17304  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
17305  9, TrainID)))
17306  {
17307  Utilities->CallLogPop(1998);
17308  return true;
17309  }
17310 
17311  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
17312  if(FirstPair.first > -1)
17313  {
17314  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
17315  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17316  {
17317  Utilities->CallLogPop(318);
17318  return true;
17319  }
17320  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17321  {
17322  Utilities->CallLogPop(319);
17323  return true;
17324  }
17325  }
17326  if(SecondPair.first > -1)
17327  {
17328  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
17329  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17330  {
17331  Utilities->CallLogPop(320);
17332  return true;
17333  }
17334  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17335  {
17336  Utilities->CallLogPop(321);
17337  return true;
17338  }
17339  }
17340 
17341  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
17342  7, TrainID)))
17343  {
17344  Utilities->CallLogPop(1999);
17345  return true;
17346  }
17347 
17348  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
17349  if(FirstPair.first > -1)
17350  {
17351  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
17352  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17353  {
17354  Utilities->CallLogPop(322);
17355  return true;
17356  }
17357  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17358  {
17359  Utilities->CallLogPop(323);
17360  return true;
17361  }
17362  }
17363  if(SecondPair.first > -1)
17364  {
17365  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
17366  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17367  {
17368  Utilities->CallLogPop(324);
17369  return true;
17370  }
17371  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17372  {
17373  Utilities->CallLogPop(325);
17374  return true;
17375  }
17376  }
17377 
17378  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
17379  3, TrainID)))
17380  {
17381  Utilities->CallLogPop(2000);
17382  return true;
17383  }
17384 
17385  Utilities->CallLogPop(326);
17386  return false;
17387 }
17388 
17389 // ---------------------------------------------------------------------------
17390 
17391 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17392 /*
17393  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
17394  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17395  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17396  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17397  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17398  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17399  Each of these is examined in turn for each route element in the relevant position.
17400 */
17401 {
17402  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17403  "," + AnsiString(DiagonalLinkNumber));
17404  TPrefDirElement TempPrefDirElement;
17405  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17406 
17407  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
17408  if(FirstPair.first > -1)
17409  {
17410  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
17411  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17412  {
17413  Utilities->CallLogPop(2010);
17414  return true;
17415  }
17416  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17417  {
17418  Utilities->CallLogPop(2011);
17419  return true;
17420  }
17421  }
17422  if(SecondPair.first > -1)
17423  {
17424  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
17425  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17426  {
17427  Utilities->CallLogPop(2012);
17428  return true;
17429  }
17430  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17431  {
17432  Utilities->CallLogPop(2013);
17433  return true;
17434  }
17435  }
17436 
17437  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
17438  if(FirstPair.first > -1)
17439  {
17440  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
17441  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17442  {
17443  Utilities->CallLogPop(2014);
17444  return true;
17445  }
17446  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17447  {
17448  Utilities->CallLogPop(2015);
17449  return true;
17450  }
17451  }
17452  if(SecondPair.first > -1)
17453  {
17454  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
17455  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17456  {
17457  Utilities->CallLogPop(2016);
17458  return true;
17459  }
17460  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17461  {
17462  Utilities->CallLogPop(2017);
17463  return true;
17464  }
17465  }
17466 
17467  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
17468  if(FirstPair.first > -1)
17469  {
17470  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
17471  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17472  {
17473  Utilities->CallLogPop(2018);
17474  return true;
17475  }
17476  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17477  {
17478  Utilities->CallLogPop(2019);
17479  return true;
17480  }
17481  }
17482  if(SecondPair.first > -1)
17483  {
17484  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
17485  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17486  {
17487  Utilities->CallLogPop(2020);
17488  return true;
17489  }
17490  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17491  {
17492  Utilities->CallLogPop(2021);
17493  return true;
17494  }
17495  }
17496 
17497  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
17498  if(FirstPair.first > -1)
17499  {
17500  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
17501  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17502  {
17503  Utilities->CallLogPop(2022);
17504  return true;
17505  }
17506  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17507  {
17508  Utilities->CallLogPop(2023);
17509  return true;
17510  }
17511  }
17512  if(SecondPair.first > -1)
17513  {
17514  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
17515  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17516  {
17517  Utilities->CallLogPop(2024);
17518  return true;
17519  }
17520  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17521  {
17522  Utilities->CallLogPop(2025);
17523  return true;
17524  }
17525  }
17526 
17527  Utilities->CallLogPop(2026);
17528  return false;
17529 }
17530 
17531 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:7596
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:676
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:476
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15677
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1173
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:908
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:463
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:9793
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:662
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:612
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:564
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:9766
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:351
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:485
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:352
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:867
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:4928
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11248
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:764
TFixedTrackPiece
Definition: TrackUnit.h:80
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:107
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1574
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12337
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:182
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:696
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:408
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:899
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6324
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:16280
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:90
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:783
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:900
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:8453
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:785
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:16686
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:911
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1231
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:508
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:688
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:580
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:701
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:11507
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:751
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:619
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:703
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:349
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11288
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:678
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3544
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:699
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:394
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:453
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:13752
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:686
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6177
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1492
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:466
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:683
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1554
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:624
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5064
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5091
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1377
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:505
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1515
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:64
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:818
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:839
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1645
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:741
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:8765
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:14989
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:611
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:897
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:17391
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:351
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1545
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:523
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2449
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:483
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:470
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5220
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:671
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:459
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:149
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:6967
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1387
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:384
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:561
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:16113
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:755
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:497
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:665
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:11045
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:359
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6470
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:482
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:400
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8580
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:7950
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12138
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:13949
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:565
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16474
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:849
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:847
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:493
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1496
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:865
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:547
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:10849
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:156
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:512
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:3990
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3249
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:672
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:823
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1399
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:458
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:581
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:752
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:465
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:788
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:6784
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:357
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:164
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:661
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:584
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4149
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1187
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:9199
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:653
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:516
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:860
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3144
Unused
@ Unused
Definition: TrackUnit.h:63
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:586
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:616
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1186
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:489
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:704
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:16926
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2480
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:762
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:252
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17117
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:493
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8107
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1553
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1397
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1483
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:219
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:909
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:660
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:355
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:812
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2872
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:15501
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:769
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:668
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:499
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Definition: TrackUnit.cpp:7208
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11111
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:690
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:443
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:477
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:786
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2496
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:626
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:997
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:16225
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:767
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:811
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:424
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1219
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:705
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11339
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1453
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:594
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5180
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:669
TTrain
Definition: TrainUnit.h:271
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:313
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:12005
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:503
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:96
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:151
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:9807
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:492
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:560
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:489
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:834
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:542
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6485
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:415
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:346
GapJump
@ GapJump
Definition: TrackUnit.h:63
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:442
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:782
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:16584
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:15450
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:848
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:147
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:471
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:912
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:457
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:147
TTrack::Raising
@ Raising
Definition: TrackUnit.h:523
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:627
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:487
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:8834
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:557
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1401
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1365
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15473
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:697
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:365
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:633
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:499
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:692
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:385
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:753
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:452
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:714
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1263
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5411
End
@ End
Definition: TrackUnit.h:73
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1403
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:667
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:835
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers
Definition: TrackUnit.h:534
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:7412
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:856
TTrack::LCFoundInAutoSigsRouteMessageGiven
bool LCFoundInAutoSigsRouteMessageGiven
true if message given to user, to avoid giving multiple times and to avoid other failure messages bei...
Definition: TrackUnit.h:651
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:895
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:482
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:8940
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1010
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:295
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:792
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:639
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:698
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:577
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:905
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:123
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:722
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:491
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:750
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3408
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:981
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:754
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:982
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:524
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:700
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8072
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:991
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:461
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:15627
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:421
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:770
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:863
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1519
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:784
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:819
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6499
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:456
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
Definition: TrackUnit.h:583
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:403
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:254
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:490
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:684
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7450
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:898
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:809
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:15612
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:748
Concourse
@ Concourse
Definition: TrackUnit.h:64
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:656
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:707
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:793
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:72
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:11795
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:11533
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:202
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:713
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:803
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:62
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:502
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4074
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1597
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:427
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:806
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:433
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:821
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:480
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:593
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:796
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:349
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:494
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:672
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:472
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:92
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:430
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:808
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:574
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:9384
TTrackElement::TempMarker
bool TempMarker
Utility marker for program use.
Definition: TrackUnit.h:135
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:16431
TTrack::TActiveLevelCrossing::TrainPassed
bool TrainPassed
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:532
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:15202
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4307
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:156
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1616
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:673
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:781
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:916
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:477
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:585
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:719
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:827
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:382
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
Definition: TrackUnit.cpp:9620
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:17023
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1008
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:610
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2464
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:709
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1409
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:6456
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:13035
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6205
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7398
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:6284
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:666
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:720
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:607
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:659
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:598
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1189
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:754
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:795
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:509
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:794
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:469
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:11423
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:758
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:859
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:10598
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1520
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1572
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:896
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:587
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:11078
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:12617
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:651
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:15406
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3226
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:141
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:11486
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:9667
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:9072
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1499
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:756
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:815
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Plot & open (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5618
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:532
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:495
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:496
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5274
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:813
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:10898
Under
@ Under
Definition: TrackUnit.h:73
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:449
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:14958
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:707
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:695
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:538
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:131
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2517
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:9819
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:10141
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:863
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:346
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:133
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:117
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:8975
Lead
@ Lead
Definition: TrackUnit.h:73
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5139
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1533
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:11732
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:772
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:527
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3434
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:217
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:4971
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:83
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1222
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:7884
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:467
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:468
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:578
TTrack::Up
@ Up
Definition: TrackUnit.h:523
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:855
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:709
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:500
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
Definition: TrackUnit.cpp:8954
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:915
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1359
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:339
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7365
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1513
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:649
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:215
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1503
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:362
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:773
Crossover
@ Crossover
Definition: TrackUnit.h:63
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:474
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:445
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:711
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:622
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:7311
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:775
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6233
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:8426
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:451
Signal
@ Signal
Definition: TrackUnit.h:73
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:487
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:505
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:460
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:679
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15915
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:151
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1261
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:10948
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:505
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:9561
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4158
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:485
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:8927
TGraphicElement::Width
int Width
Definition: TrackUnit.h:353
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:16810
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:519
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:17007
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:15740
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:684
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:487
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:726
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:569
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:446
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3718
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:468
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:763
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:570
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3696
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2058
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:605
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:464
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:8008
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:10729
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:588
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:406
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:854
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:842
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5115
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17090
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:567
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:5843
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1401
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:902
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:761
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1390
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:820
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5950
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:470
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:653
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1021
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1023
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:513
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:6661
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:15560
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:571
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:421
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6306
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:777
Erase
@ Erase
Definition: TrackUnit.h:64
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:824
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:397
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:479
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:4795
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:707
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1552
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:123
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:804
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:851
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:575
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:11554
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:9474
Parapet
@ Parapet
Definition: TrackUnit.h:64
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:447
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:15585
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:778
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:985
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7693
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:15535
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:377
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:844
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:707
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:16452
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:590
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:907
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:682
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:776
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:145
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:478
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:799
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:241
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:549
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1026
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:634
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:791
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:13564
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:816
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:217
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:9695
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:10656
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:504
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1167
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:496
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:596
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:475
TTrack
Definition: TrackUnit.h:463
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1230
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:754
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1237
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:16600
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1490
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:6936
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:620
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:503
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:833
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:650
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:842
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:126
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:798
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:515
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:685
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:215
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:16091
TTrack::TActiveLevelCrossing::ConsecSignals
bool ConsecSignals
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs)
Definition: TrackUnit.h:530
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:223
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2596
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:450
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7896
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:901
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:5512
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1823
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:131
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:502
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:724
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:156
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:837
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:690
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2281
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:213
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1488
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:6633
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:481
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:10444
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11201
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:501
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1365
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:8864
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:7274
IDInt
Definition: TrackUnit.h:412
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2281
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:573
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:17058
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:597
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:771
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3965
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:8674
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4570
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:143
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:789
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:765
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:814
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:355
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:17155
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:894
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:7809
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:121
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:485
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:95
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:6582
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1168
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:221
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:151
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:878
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:668
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:380
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:631
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:221
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:392
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:840
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1557
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:154
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:128
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:760
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6550
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:544
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:801
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:774
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:715
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:145
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:788
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:747
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1376
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:831
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1494
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:828
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1504
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:436
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4229
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:570
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Definition: TrackUnit.cpp:7632
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:639
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:13556
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1195
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:716
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:349
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:11660
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:805
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1174
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:149
Points
@ Points
Definition: TrackUnit.h:63
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:702
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:13071
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:723
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:16165
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:846
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:8357
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:9544
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:409
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:582
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:813
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:498
Trail
@ Trail
Definition: TrackUnit.h:73
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:7866
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:15070
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:754
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1569
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:497
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:797
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:14895
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:810
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:647
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:418
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:725
Continuation
@ Continuation
Definition: TrackUnit.h:63
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1017
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:6429
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:46
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3326
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5351
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:355
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:7913
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:845
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:853
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:861
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:10487
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:491
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:815
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:745
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:850
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:349
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6097
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1006
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2962
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:353
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:866
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1393
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:85
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:455
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:688
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:609
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:636
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1551
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:903
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:368
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:294
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:829
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:17213
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:486
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:11387
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:995
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:484
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:759
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1367
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:999
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:349
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:448
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:674
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:615
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:782
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4214
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:864
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:16062
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1584
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:698
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:121
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:576
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:694
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:652
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:198
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:9338
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:803
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:617
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1232
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:17074
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:495
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1579
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4199
Connection
@ Connection
Definition: TrackUnit.h:73
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3303
TPrefDirElement::ConsecSignals
bool ConsecSignals
marker within the route for ConsecSignalsRoute element
Definition: TrackUnit.h:256
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:358
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1559
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:8125
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:986
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:500
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:14705
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:10318
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:706
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:802
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:7338
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:852
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1004
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16376
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:16332
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6023
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:460
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:9225
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:691
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:843
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:630
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1220
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:875
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:485
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5159
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:836
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:707
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:444
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:254
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:349
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:661
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:8480
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:487
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:632
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:643
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:15599
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4339
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:780
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2384
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:674
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6510
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:386
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2724
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:374
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:832
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:130
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:857
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:371
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:14866
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:540
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:11912
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:265
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:348
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:659
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:589
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:606
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:613
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:393
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:488
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1168
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:565
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:462
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:575
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:891
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:624
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:9898
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:454
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:349
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:514
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:910
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:98
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:828
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1363
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:210
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:790
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1477
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:7490
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:625
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:571
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:621
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:11631
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:17042
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise points: 0=set to ...
Definition: TrackUnit.h:139
TTrack::TBarrierState
TBarrierState
< state of barriers
Definition: TrackUnit.h:522
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1229
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4094
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:700
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4091
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1670
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:525
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1012
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:983
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:694
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:817
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:626
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:6261
Platform
@ Platform
Definition: TrackUnit.h:63
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1237
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:223
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:577
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:862
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:665
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:635
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4116
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:676
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1498
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1019
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:757
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:913
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:6889
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:664
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1181
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:787
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:822
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8046
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:993
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:746
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:9439
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1484
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:807
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:623
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1365
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:347
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:702
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:147
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:772
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:141
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:677
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1367
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:527
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:708
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3203
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:749
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:642
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:98
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:111
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:498
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:779
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:647
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9371
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:766
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:858
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:826
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:147
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:593
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:904
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:251
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:693
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:536
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:712
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:850
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:412
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:566
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:87
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:14323
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:600
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:705
RouteCall
@ RouteCall
Definition: TrackUnit.h:1174
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:387
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:9832
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:838
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:250
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:591
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:501
NotSet
@ NotSet
Definition: TrackUnit.h:73
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
concourses, non-station named locations & parapets)
Definition: TrackUnit.h:581
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:15639
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:16646
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:213
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:390
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:592
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:579
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9400
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:8736
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:588
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:505
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:213
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:768
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:906
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5576
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:156
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:64
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:914
TRailGraphics::smTransparent
Graphics::TBitmap * smTransparent
Definition: GraphicUnit.h:880
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:641
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:9844
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1234
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:391
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:141
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1243
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:830
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:721
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:800
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:692
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:487
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:614
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:8727
Bridge
@ Bridge
Definition: TrackUnit.h:63
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:841
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:439
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1168
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:789
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:523
Gap
@ Gap
Definition: TrackUnit.h:73
Buffers
@ Buffers
Definition: TrackUnit.h:63
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:14629
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:689
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:73
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:9856
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:13967
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:473
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4029
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:9779
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:825